2012-08-11 13:24:08 +00:00
|
|
|
/********************************************************************************
|
2011-07-11 09:33:18 +00:00
|
|
|
* *
|
|
|
|
|
* This file is part of IfcOpenShell. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the Lesser GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* Lesser GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the Lesser GNU General Public License *
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
|
|
|
* *
|
|
|
|
|
********************************************************************************/
|
2011-05-08 11:04:32 +00:00
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
#include <set>
|
2012-03-13 11:56:52 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <string>
|
2011-07-25 14:56:40 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2012-11-17 15:19:38 +00:00
|
|
|
#include <ctime>
|
2017-06-05 17:26:58 +02:00
|
|
|
#include <boost/circular_buffer.hpp>
|
2011-07-25 14:56:40 +00:00
|
|
|
|
2012-12-31 11:47:46 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-09-13 15:00:21 +02:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2016-07-15 06:49:32 +03:00
|
|
|
#include <boost/math/special_functions/fpclassify.hpp>
|
2015-09-13 15:00:21 +02:00
|
|
|
|
2011-09-25 09:53:22 +00:00
|
|
|
#include "../ifcparse/IfcCharacterDecoder.h"
|
2011-05-08 11:04:32 +00:00
|
|
|
#include "../ifcparse/IfcParse.h"
|
2011-09-25 09:53:22 +00:00
|
|
|
#include "../ifcparse/IfcException.h"
|
2017-06-05 17:26:58 +02:00
|
|
|
#include "../ifcparse/IfcBaseClass.h"
|
2015-01-05 14:11:42 +00:00
|
|
|
#include "../ifcparse/IfcSpfStream.h"
|
|
|
|
|
#include "../ifcparse/IfcFile.h"
|
2015-02-17 19:48:41 +00:00
|
|
|
#include "../ifcparse/IfcSIPrefix.h"
|
2011-05-08 11:04:32 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
#ifdef USE_IFC4
|
|
|
|
|
#include "../ifcparse/Ifc4-latebound.h"
|
|
|
|
|
#else
|
|
|
|
|
#include "../ifcparse/Ifc2x3-latebound.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-06-12 11:22:08 +02:00
|
|
|
#define PERMISSIVE_FLOAT
|
|
|
|
|
|
2011-05-08 11:04:32 +00:00
|
|
|
using namespace IfcParse;
|
|
|
|
|
|
2015-02-03 13:53:36 +00:00
|
|
|
// A static locale for the real number parser. strtod() is locale-dependent, causing issues
|
|
|
|
|
// in locales that have ',' as a decimal separator. Therefore the non standard _strtod_l() /
|
|
|
|
|
// strtod_l() is used and a reference to the "C" locale is obtained here. The alternative is
|
|
|
|
|
// to use std::istringstream::imbue(std::locale::classic()), but there are subtleties in
|
|
|
|
|
// parsing in MSVC2010 and it appears to be much slower.
|
2016-06-05 14:03:03 +02:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
|
|
2015-02-03 13:53:36 +00:00
|
|
|
static _locale_t locale = (_locale_t) 0;
|
|
|
|
|
void init_locale() {
|
|
|
|
|
if (locale == (_locale_t) 0) {
|
|
|
|
|
locale = _create_locale(LC_NUMERIC, "C");
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-29 17:58:03 +01:00
|
|
|
|
2016-06-05 14:03:03 +02:00
|
|
|
#else
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2016-06-05 14:03:03 +02:00
|
|
|
#if defined(__MINGW64__) || defined(__MINGW32__)
|
2016-05-29 17:58:03 +01:00
|
|
|
#include <locale>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
typedef void* locale_t;
|
2016-06-05 14:03:03 +02:00
|
|
|
static locale_t locale = (locale_t)0;
|
2016-05-29 17:58:03 +01:00
|
|
|
|
|
|
|
|
void init_locale() {}
|
|
|
|
|
|
|
|
|
|
double strtod_l(const char* start, char** end, locale_t loc) {
|
2016-06-05 14:03:03 +02:00
|
|
|
double d;
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss.imbue(std::locale::classic());
|
|
|
|
|
ss << start;
|
|
|
|
|
ss >> d;
|
|
|
|
|
size_t nread = ss.tellg();
|
|
|
|
|
*end = const_cast<char*>(start) + nread;
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
#include <xlocale.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <locale.h>
|
|
|
|
|
|
|
|
|
|
static locale_t locale = (locale_t)0;
|
|
|
|
|
void init_locale() {
|
|
|
|
|
if (locale == (locale_t)0) {
|
|
|
|
|
locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
|
|
|
|
|
}
|
2016-05-29 17:58:03 +01:00
|
|
|
}
|
2016-06-05 14:03:03 +02:00
|
|
|
|
2016-05-29 17:58:03 +01:00
|
|
|
#endif
|
|
|
|
|
|
2016-06-05 14:03:03 +02:00
|
|
|
#endif
|
2016-05-29 17:58:03 +01:00
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
|
|
|
|
// Opens the file, gets the filesize and reads a chunk in memory
|
|
|
|
|
//
|
2016-03-05 00:40:08 +02:00
|
|
|
IfcSpfStream::IfcSpfStream(const std::string& fn)
|
2016-06-09 22:25:50 +06:00
|
|
|
: stream(0)
|
|
|
|
|
, buffer(0)
|
2016-03-05 00:40:08 +02:00
|
|
|
{
|
2011-07-11 09:33:18 +00:00
|
|
|
eof = false;
|
2012-12-31 11:47:46 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
int fn_buffer_size = MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, 0, 0);
|
|
|
|
|
wchar_t* fn_wide = new wchar_t[fn_buffer_size];
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, fn.c_str(), -1, fn_wide, fn_buffer_size);
|
|
|
|
|
stream = _wfopen(fn_wide, L"rb");
|
|
|
|
|
delete[] fn_wide;
|
|
|
|
|
#else
|
|
|
|
|
stream = fopen(fn.c_str(), "rb");
|
|
|
|
|
#endif
|
|
|
|
|
if (stream == NULL) {
|
2011-08-07 10:21:22 +00:00
|
|
|
valid = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
valid = true;
|
2012-12-31 11:47:46 +00:00
|
|
|
fseek(stream, 0, SEEK_END);
|
2016-03-05 00:40:08 +02:00
|
|
|
size = (unsigned int) ftell(stream);
|
2012-12-31 11:47:46 +00:00
|
|
|
rewind(stream);
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
|
|
|
|
offset = 0;
|
2011-08-20 09:08:56 +00:00
|
|
|
paging = size > BUF_SIZE;
|
2011-07-11 09:33:18 +00:00
|
|
|
buffer = new char[size < BUF_SIZE ? size : BUF_SIZE];
|
2012-05-26 09:00:30 +00:00
|
|
|
#else
|
|
|
|
|
buffer = new char[size];
|
|
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
ptr = 0;
|
2016-03-05 00:40:08 +02:00
|
|
|
len = 0;
|
2011-07-11 09:33:18 +00:00
|
|
|
ReadBuffer(false);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-05 00:40:08 +02:00
|
|
|
IfcSpfStream::IfcSpfStream(std::istream& f, int l)
|
2016-06-09 22:25:50 +06:00
|
|
|
: stream(0)
|
|
|
|
|
, buffer(0)
|
2016-03-05 00:40:08 +02:00
|
|
|
{
|
2011-08-20 09:08:56 +00:00
|
|
|
eof = false;
|
|
|
|
|
size = l;
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-08-20 09:08:56 +00:00
|
|
|
paging = false;
|
2012-05-26 09:00:30 +00:00
|
|
|
offset = 0;
|
|
|
|
|
#endif
|
2011-08-20 09:08:56 +00:00
|
|
|
buffer = new char[size];
|
|
|
|
|
f.read(buffer,size);
|
|
|
|
|
valid = f.gcount() == size;
|
|
|
|
|
ptr = 0;
|
2012-05-26 09:00:30 +00:00
|
|
|
len = l;
|
2011-08-20 09:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-05 00:40:08 +02:00
|
|
|
IfcSpfStream::IfcSpfStream(void* data, int l)
|
2016-06-09 22:25:50 +06:00
|
|
|
: stream(0)
|
|
|
|
|
, buffer(0)
|
2016-03-05 00:40:08 +02:00
|
|
|
{
|
2011-10-27 16:13:29 +00:00
|
|
|
eof = false;
|
|
|
|
|
size = l;
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-10-27 16:13:29 +00:00
|
|
|
paging = false;
|
2012-05-26 09:00:30 +00:00
|
|
|
offset = 0;
|
|
|
|
|
#endif
|
2011-10-27 16:13:29 +00:00
|
|
|
buffer = (char*) data;
|
|
|
|
|
valid = true;
|
|
|
|
|
ptr = 0;
|
2016-03-05 00:40:08 +02:00
|
|
|
len = l;
|
2011-10-27 16:13:29 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-07 22:45:42 +02:00
|
|
|
IfcSpfStream::~IfcSpfStream()
|
|
|
|
|
{
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
void IfcSpfStream::Close() {
|
|
|
|
|
#ifdef BUF_SIZE
|
2012-12-31 11:47:46 +00:00
|
|
|
if ( paging ) fclose(stream);
|
2012-08-11 13:24:08 +00:00
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
delete[] buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Reads a chunk of BUF_SIZE in memory and increments cursor if requested
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
void IfcSpfStream::ReadBuffer(bool inc) {
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-07-11 09:33:18 +00:00
|
|
|
if ( inc ) {
|
|
|
|
|
offset += len;
|
2012-12-31 11:47:46 +00:00
|
|
|
fseek(stream, offset, SEEK_SET);
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
2015-11-23 15:52:12 +02:00
|
|
|
#else
|
|
|
|
|
(void)inc;
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2012-12-31 11:47:46 +00:00
|
|
|
eof = feof(stream) != 0;
|
2011-07-11 09:33:18 +00:00
|
|
|
if ( eof ) return;
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2012-12-31 11:47:46 +00:00
|
|
|
len = (unsigned int) fread(buffer, 1, size < BUF_SIZE ? size : BUF_SIZE, stream);
|
2012-05-26 09:00:30 +00:00
|
|
|
#else
|
2012-12-31 11:47:46 +00:00
|
|
|
len = (unsigned int) fread(buffer, 1, size, stream);
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
eof = len == 0;
|
|
|
|
|
ptr = 0;
|
2012-08-11 13:24:08 +00:00
|
|
|
#ifdef BUF_SIZE
|
2012-12-31 11:47:46 +00:00
|
|
|
if (!paging) fclose(stream);
|
2012-08-11 13:24:08 +00:00
|
|
|
#else
|
2012-12-31 11:47:46 +00:00
|
|
|
fclose(stream);
|
2012-08-11 13:24:08 +00:00
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Seeks an arbitrary position in the file
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
void IfcSpfStream::Seek(unsigned int o) {
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-08-20 09:08:56 +00:00
|
|
|
if ( !paging ) {
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2011-08-20 09:08:56 +00:00
|
|
|
ptr = o;
|
2012-02-04 15:10:17 +00:00
|
|
|
if (ptr >= len) throw IfcException("Reading outside of file limits");
|
2011-08-20 09:08:56 +00:00
|
|
|
eof = false;
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-08-20 09:08:56 +00:00
|
|
|
} else if ( o >= offset && (o < (offset+len)) ) {
|
2011-07-11 09:33:18 +00:00
|
|
|
ptr = o - offset;
|
|
|
|
|
} else {
|
|
|
|
|
offset = o;
|
2012-12-31 11:47:46 +00:00
|
|
|
clearerr(stream);
|
|
|
|
|
fseek(stream, o, SEEK_SET);
|
2011-07-11 09:33:18 +00:00
|
|
|
ReadBuffer(false);
|
|
|
|
|
}
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Returns the character at the cursor
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
char IfcSpfStream::Peek() {
|
2011-07-11 09:33:18 +00:00
|
|
|
return buffer[ptr];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Returns the character at specified offset
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
char IfcSpfStream::Read(unsigned int o) {
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-08-20 09:08:56 +00:00
|
|
|
if ( ! paging ) {
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2012-02-04 15:10:17 +00:00
|
|
|
return buffer[o];
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-08-20 09:08:56 +00:00
|
|
|
} else if ( o >= offset && (o < (offset+len)) ) {
|
2011-07-11 09:33:18 +00:00
|
|
|
return buffer[o-offset];
|
2011-05-08 11:04:32 +00:00
|
|
|
} else {
|
2012-12-31 11:47:46 +00:00
|
|
|
clearerr(stream);
|
|
|
|
|
fseek(stream, o, SEEK_SET);
|
|
|
|
|
return ungetc(getc(stream), stream);
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Returns the cursor position
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
unsigned int IfcSpfStream::Tell() {
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-07-11 09:33:18 +00:00
|
|
|
return offset + ptr;
|
2012-05-26 09:00:30 +00:00
|
|
|
#else
|
|
|
|
|
return ptr;
|
|
|
|
|
#endif
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Increments cursor and reads new chunk if necessary
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
void IfcSpfStream::Inc() {
|
2011-08-20 09:08:56 +00:00
|
|
|
if ( ++ptr == len ) {
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2011-08-20 09:08:56 +00:00
|
|
|
if ( paging ) ReadBuffer();
|
2012-02-04 15:10:17 +00:00
|
|
|
else {
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2012-02-04 15:10:17 +00:00
|
|
|
eof = true;
|
|
|
|
|
return;
|
2012-05-26 09:00:30 +00:00
|
|
|
#ifdef BUF_SIZE
|
2012-02-04 15:10:17 +00:00
|
|
|
}
|
2012-05-26 09:00:30 +00:00
|
|
|
#endif
|
2011-08-20 09:08:56 +00:00
|
|
|
}
|
2012-08-11 13:24:08 +00:00
|
|
|
const char current = IfcSpfStream::Peek();
|
|
|
|
|
if ( current == '\n' || current == '\r' ) IfcSpfStream::Inc();
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
IfcSpfLexer::IfcSpfLexer(IfcParse::IfcSpfStream *s, IfcParse::IfcFile* f) {
|
2011-07-11 09:33:18 +00:00
|
|
|
file = f;
|
2012-08-11 13:24:08 +00:00
|
|
|
stream = s;
|
|
|
|
|
decoder = new IfcCharacterDecoder(s);
|
2011-09-25 09:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
IfcSpfLexer::~IfcSpfLexer() {
|
2011-09-25 09:53:22 +00:00
|
|
|
delete decoder;
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
unsigned int IfcSpfLexer::skipWhitespace() {
|
2014-04-02 15:04:09 +00:00
|
|
|
unsigned int n = 0;
|
|
|
|
|
while ( !stream->eof ) {
|
|
|
|
|
char c = stream->Peek();
|
|
|
|
|
if ( (c == ' ' || c == '\r' || c == '\n' || c == '\t' ) ) {
|
|
|
|
|
stream->Inc();
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
else break;
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
unsigned int IfcSpfLexer::skipComment() {
|
2014-04-02 15:04:09 +00:00
|
|
|
char c = stream->Peek();
|
|
|
|
|
if (c != '/') return 0;
|
|
|
|
|
stream->Inc();
|
|
|
|
|
c = stream->Peek();
|
|
|
|
|
if (c != '*') {
|
|
|
|
|
stream->Seek(stream->Tell() - 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
unsigned int n = 2;
|
|
|
|
|
char p = 0;
|
|
|
|
|
while ( !stream->eof ) {
|
|
|
|
|
c = stream->Peek();
|
|
|
|
|
stream->Inc();
|
|
|
|
|
++ n;
|
|
|
|
|
if (c == '/' && p == '*') break;
|
|
|
|
|
p = c;
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
|
|
|
|
// Returns the offset of the current Token and moves cursor to next
|
|
|
|
|
//
|
2015-01-05 17:46:23 +00:00
|
|
|
Token IfcSpfLexer::Next() {
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2016-06-09 22:25:50 +06:00
|
|
|
if ( stream->eof ) return NoneTokenPtr();
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2014-04-02 15:04:09 +00:00
|
|
|
while (skipWhitespace() || skipComment()) {}
|
|
|
|
|
|
2016-06-09 22:25:50 +06:00
|
|
|
if ( stream->eof ) return NoneTokenPtr();
|
2012-08-11 13:24:08 +00:00
|
|
|
unsigned int pos = stream->Tell();
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2014-04-02 15:04:09 +00:00
|
|
|
char c = stream->Peek();
|
|
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
// If the cursor is at [()=,;$*] we know token consists of single char
|
2014-04-19 09:35:08 +00:00
|
|
|
if (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '$' || c == '*') {
|
2012-08-11 13:24:08 +00:00
|
|
|
stream->Inc();
|
2016-06-09 22:25:50 +06:00
|
|
|
return OperatorTokenPtr(this, pos, pos+1);
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int len = 0;
|
|
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
while ( ! stream->eof ) {
|
2011-07-11 09:33:18 +00:00
|
|
|
|
|
|
|
|
// Read character and increment pointer if not starting a new token
|
2015-11-21 23:05:28 +02:00
|
|
|
c = stream->Peek();
|
2014-04-19 09:35:08 +00:00
|
|
|
if ( len && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '/') ) break;
|
2012-08-11 13:24:08 +00:00
|
|
|
stream->Inc();
|
2011-07-11 09:33:18 +00:00
|
|
|
len ++;
|
|
|
|
|
|
2014-04-02 15:04:09 +00:00
|
|
|
// If a string is encountered defer processing to the IfcCharacterDecoder
|
|
|
|
|
if ( c == '\'' ) decoder->dryRun();
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
2016-06-09 22:25:50 +06:00
|
|
|
if ( len ) return GeneralTokenPtr(this, pos, stream->Tell());
|
|
|
|
|
else return NoneTokenPtr();
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Reads a std::string from the file at specified offset
|
|
|
|
|
// Omits whitespace and comments
|
|
|
|
|
//
|
2016-06-09 22:25:50 +06:00
|
|
|
void IfcSpfLexer::TokenString(unsigned int offset, std::string &buffer) {
|
2012-08-11 13:24:08 +00:00
|
|
|
const bool was_eof = stream->eof;
|
|
|
|
|
unsigned int old_offset = stream->Tell();
|
|
|
|
|
stream->Seek(offset);
|
2016-06-09 22:25:50 +06:00
|
|
|
buffer.clear();
|
2012-08-11 13:24:08 +00:00
|
|
|
while ( ! stream->eof ) {
|
|
|
|
|
char c = stream->Peek();
|
2014-04-19 09:35:08 +00:00
|
|
|
if ( buffer.size() && (c == '(' || c == ')' || c == '=' || c == ',' || c == ';' || c == '/') ) break;
|
2012-08-11 13:24:08 +00:00
|
|
|
stream->Inc();
|
2014-04-02 15:04:09 +00:00
|
|
|
if ( c == ' ' || c == '\r' || c == '\n' || c == '\t' ) continue;
|
2016-06-09 22:25:50 +06:00
|
|
|
else if ( c == '\'' ) {
|
|
|
|
|
buffer = *decoder;
|
2017-06-05 17:26:58 +02:00
|
|
|
break;
|
2016-06-09 22:25:50 +06:00
|
|
|
}
|
2014-04-02 15:04:09 +00:00
|
|
|
else buffer.push_back(c);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2012-08-11 13:24:08 +00:00
|
|
|
if ( was_eof ) stream->eof = true;
|
|
|
|
|
else stream->Seek(old_offset);
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-09 22:25:50 +06:00
|
|
|
//Note: according to STEP standard, there may be newlines in tokens
|
|
|
|
|
inline void RemoveTokenSeparators(IfcSpfStream* stream, unsigned start, unsigned end, std::string &oDestination) {
|
|
|
|
|
oDestination.clear();
|
|
|
|
|
for (unsigned i = start; i < end; i++) {
|
|
|
|
|
char c = stream->Read(i);
|
|
|
|
|
if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
|
|
|
|
|
continue;
|
|
|
|
|
oDestination += c;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2016-06-09 22:25:50 +06:00
|
|
|
bool ParseInt(const char *pStart, int &val) {
|
|
|
|
|
char* pEnd;
|
|
|
|
|
long result = strtol(pStart, &pEnd, 10);
|
|
|
|
|
if (*pEnd != 0)
|
|
|
|
|
return false;
|
|
|
|
|
val = (int)result;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ParseFloat(const char *pStart, double &val) {
|
|
|
|
|
char* pEnd;
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
double result = _strtod_l(pStart, &pEnd, locale);
|
|
|
|
|
#else
|
|
|
|
|
double result = strtod_l(pStart, &pEnd, locale);
|
|
|
|
|
#endif
|
|
|
|
|
if (*pEnd != 0)
|
|
|
|
|
return false;
|
|
|
|
|
val = result;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ParseBool(const char *pStart, bool &val) {
|
|
|
|
|
if (strlen(pStart) != 3 || pStart[0] != '.' || pStart[2] != '.')
|
|
|
|
|
return false;
|
|
|
|
|
char mid = pStart[1];
|
2016-06-20 11:34:13 +02:00
|
|
|
/// @todo https://github.com/IfcOpenShell/IfcOpenShell/issues/95
|
|
|
|
|
if (!(mid == 'T' || mid == 'F' || mid == 'U'))
|
2016-06-09 22:25:50 +06:00
|
|
|
return false;
|
|
|
|
|
val = (mid == 'T');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Token IfcParse::OperatorTokenPtr(IfcSpfLexer* lexer, unsigned start, unsigned end) {
|
|
|
|
|
char first = lexer->stream->Read(start);
|
|
|
|
|
Token token(lexer, start, end, Token_OPERATOR);
|
|
|
|
|
token.value_char = first;
|
|
|
|
|
return token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Token IfcParse::GeneralTokenPtr(IfcSpfLexer* lexer, unsigned start, unsigned end) {
|
|
|
|
|
Token token(lexer, start, end, Token_NONE);
|
|
|
|
|
|
|
|
|
|
//extract token into temp buffer (remove eol-s, no encoding changes)
|
|
|
|
|
std::string &tokenStr = lexer->GetTempString();
|
|
|
|
|
RemoveTokenSeparators(lexer->stream, start, end, tokenStr);
|
|
|
|
|
|
|
|
|
|
//determine type of the token
|
|
|
|
|
char first = lexer->stream->Read(start);
|
|
|
|
|
if (first == '#') {
|
|
|
|
|
token.type = Token_IDENTIFIER;
|
|
|
|
|
if (!ParseInt(tokenStr.c_str() + 1, token.value_int))
|
|
|
|
|
throw IfcException("Identifier token as not integer");
|
|
|
|
|
}
|
|
|
|
|
else if (first == '\'')
|
|
|
|
|
token.type = Token_STRING;
|
|
|
|
|
else if (first == '.') {
|
|
|
|
|
token.type = Token_ENUMERATION;
|
|
|
|
|
if (ParseBool(tokenStr.c_str(), token.value_bool)) //bool is also enumeration
|
|
|
|
|
token.type = Token_BOOL;
|
|
|
|
|
}
|
|
|
|
|
else if (first == '"')
|
|
|
|
|
token.type = Token_BINARY;
|
|
|
|
|
else if (ParseInt(tokenStr.c_str(), token.value_int))
|
|
|
|
|
token.type = Token_INT;
|
|
|
|
|
else if (ParseFloat(tokenStr.c_str(), token.value_double))
|
|
|
|
|
token.type = Token_FLOAT;
|
|
|
|
|
else
|
|
|
|
|
token.type = Token_KEYWORD;
|
|
|
|
|
|
|
|
|
|
return token;
|
|
|
|
|
}
|
|
|
|
|
Token IfcParse::NoneTokenPtr() { return Token(); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool TokenFunc::isOperator(const Token& t) {
|
|
|
|
|
return t.type == Token_OPERATOR;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool TokenFunc::isOperator(const Token& t, char op) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_OPERATOR && t.value_char == op;
|
2011-06-13 07:23:09 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool TokenFunc::isIdentifier(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_IDENTIFIER;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool TokenFunc::isString(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_STRING;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool TokenFunc::isEnumeration(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_ENUMERATION || t.type == Token_BOOL;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2015-04-07 15:06:56 +00:00
|
|
|
bool TokenFunc::isBinary(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_BINARY;
|
2015-04-07 15:06:56 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
bool TokenFunc::isKeyword(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_KEYWORD;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2014-11-02 18:36:51 +00:00
|
|
|
bool TokenFunc::isInt(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_INT;
|
2014-11-02 18:36:51 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2014-11-02 18:36:51 +00:00
|
|
|
bool TokenFunc::isBool(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_BOOL;
|
2014-11-02 18:36:51 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2014-11-02 18:36:51 +00:00
|
|
|
bool TokenFunc::isFloat(const Token& t) {
|
2016-06-12 11:22:08 +02:00
|
|
|
#ifdef PERMISSIVE_FLOAT
|
|
|
|
|
/// NB: We are being more permissive here then allowed by the standard
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.type == Token_FLOAT || t.type == Token_INT;
|
2016-06-12 11:22:08 +02:00
|
|
|
#else
|
|
|
|
|
return t.type == Token_FLOAT;
|
|
|
|
|
#endif
|
2014-11-02 18:36:51 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
int TokenFunc::asInt(const Token& t) {
|
2016-06-12 11:22:08 +02:00
|
|
|
if (t.type != Token_INT) {
|
|
|
|
|
throw IfcInvalidTokenException(t.startPos, toString(t), "integer");
|
|
|
|
|
}
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.value_int;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TokenFunc::asIdentifier(const Token& t) {
|
2016-06-12 11:22:08 +02:00
|
|
|
if (t.type != Token_IDENTIFIER) {
|
|
|
|
|
throw IfcInvalidTokenException(t.startPos, toString(t), "instance name");
|
|
|
|
|
}
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.value_int;
|
2011-06-13 07:23:09 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool TokenFunc::asBool(const Token& t) {
|
2016-06-12 11:22:08 +02:00
|
|
|
if (t.type != Token_BOOL) {
|
|
|
|
|
throw IfcInvalidTokenException(t.startPos, toString(t), "boolean");
|
|
|
|
|
}
|
2016-06-09 22:25:50 +06:00
|
|
|
return t.value_bool;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
double TokenFunc::asFloat(const Token& t) {
|
2016-06-12 11:22:08 +02:00
|
|
|
#ifdef PERMISSIVE_FLOAT
|
|
|
|
|
if (t.type == Token_INT) {
|
|
|
|
|
/// NB: We are being more permissive here then allowed by the standard
|
|
|
|
|
return t.value_int;
|
|
|
|
|
} else // ----> continues beyond preprocessor directive
|
|
|
|
|
#endif
|
|
|
|
|
if (t.type == Token_FLOAT) {
|
|
|
|
|
return t.value_double;
|
|
|
|
|
} else {
|
|
|
|
|
throw IfcInvalidTokenException(t.startPos, toString(t), "real");
|
|
|
|
|
}
|
2016-06-09 22:25:50 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string &TokenFunc::asStringRef(const Token& t) {
|
2017-03-02 16:12:20 +02:00
|
|
|
if (t.type == Token_NONE) {
|
|
|
|
|
throw IfcParse::IfcException("Null token encountered, premature end of file?");
|
|
|
|
|
}
|
2016-06-09 22:25:50 +06:00
|
|
|
std::string &str = t.lexer->GetTempString();
|
|
|
|
|
t.lexer->TokenString(t.startPos, str);
|
2016-06-14 20:30:02 +02:00
|
|
|
if ((isString(t) || isEnumeration(t) || isBinary(t)) && !str.empty()) {
|
2016-06-09 22:25:50 +06:00
|
|
|
//remove start+end characters in-place
|
2016-06-14 20:30:02 +02:00
|
|
|
str.erase(str.end()-1);
|
2016-06-09 22:25:50 +06:00
|
|
|
str.erase(str.begin());
|
|
|
|
|
}
|
|
|
|
|
return str;
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
std::string TokenFunc::asString(const Token& t) {
|
2016-06-12 11:22:08 +02:00
|
|
|
if (isString(t) || isEnumeration(t) || isBinary(t)) {
|
|
|
|
|
return asStringRef(t);
|
|
|
|
|
} else {
|
|
|
|
|
throw IfcInvalidTokenException(t.startPos, toString(t), "string");
|
|
|
|
|
}
|
2015-04-07 15:06:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boost::dynamic_bitset<> TokenFunc::asBinary(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
const std::string &str = asStringRef(t);
|
2015-04-07 15:06:56 +00:00
|
|
|
if (str.size() < 1) {
|
|
|
|
|
throw IfcException("Token is not a valid binary sequence");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string::const_iterator it = str.begin();
|
|
|
|
|
int n = *it - '0';
|
|
|
|
|
if ((n < 0 || n > 3) || (str.size() == 1 && n != 0)) {
|
|
|
|
|
throw IfcException("Token is not a valid binary sequence");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++it;
|
2015-11-03 17:58:08 +02:00
|
|
|
unsigned i = ((unsigned)str.size()-1) * 4 - n;
|
2015-04-07 15:06:56 +00:00
|
|
|
boost::dynamic_bitset<> bitset(i);
|
|
|
|
|
|
|
|
|
|
for(; it != str.end(); ++it) {
|
|
|
|
|
const std::string::value_type& c = *it;
|
|
|
|
|
int value = (c < 'A') ? (c - '0') : (c - 'A' + 10);
|
|
|
|
|
for (unsigned j = 0; j < 4; ++j) {
|
|
|
|
|
if (i-- == 0) break;
|
|
|
|
|
if (value & (1 << (3-j))) {
|
|
|
|
|
bitset.set(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bitset;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-03 13:53:36 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
std::string TokenFunc::toString(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
std::string result;
|
|
|
|
|
t.lexer->TokenString(t.startPos, result);
|
|
|
|
|
return result;
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
2011-05-08 11:04:32 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
TokenArgument::TokenArgument(const Token& t) {
|
2011-07-11 09:33:18 +00:00
|
|
|
token = t;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2015-01-05 14:11:42 +00:00
|
|
|
EntityArgument::EntityArgument(const Token& t) {
|
2016-06-09 22:25:50 +06:00
|
|
|
IfcParse::IfcFile* file = t.lexer->file;
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcEntityInstanceData* data = read(0, file, t.startPos);
|
|
|
|
|
entity = IfcSchema::SchemaEntity(data);
|
|
|
|
|
// Needs to be loaded, for the tokens to be consumed
|
|
|
|
|
file->load(*data);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Reads the arguments from a list of token
|
2017-06-05 17:26:58 +02:00
|
|
|
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
2017-06-05 17:26:58 +02:00
|
|
|
void IfcParse::IfcFile::load(unsigned entity_instance_name, std::vector<Argument*>& attributes) {
|
|
|
|
|
Token next = tokens->Next();
|
2016-06-09 22:25:50 +06:00
|
|
|
while( next.startPos || next.lexer ) {
|
2015-01-16 16:26:40 +00:00
|
|
|
if ( TokenFunc::isOperator(next,',') ) {
|
|
|
|
|
// do nothing
|
|
|
|
|
} else if ( TokenFunc::isOperator(next,')') ) {
|
|
|
|
|
break;
|
|
|
|
|
} else if ( TokenFunc::isOperator(next,'(') ) {
|
2015-11-21 23:05:28 +02:00
|
|
|
ArgumentList* alist = new ArgumentList();
|
2017-06-05 17:26:58 +02:00
|
|
|
load(entity_instance_name, alist->arguments());
|
|
|
|
|
attributes.push_back(alist);
|
2015-01-16 16:26:40 +00:00
|
|
|
} else {
|
|
|
|
|
if ( TokenFunc::isIdentifier(next) ) {
|
2017-06-05 17:26:58 +02:00
|
|
|
if (!parsing_complete_) {
|
|
|
|
|
register_inverse(entity_instance_name, next);
|
|
|
|
|
}
|
2015-01-16 16:26:40 +00:00
|
|
|
} if ( TokenFunc::isKeyword(next) ) {
|
2017-06-05 17:26:58 +02:00
|
|
|
// tokens->Next();
|
2012-03-31 09:54:15 +00:00
|
|
|
try {
|
2017-06-05 17:26:58 +02:00
|
|
|
attributes.push_back(new EntityArgument(next));
|
2012-03-31 09:54:15 +00:00
|
|
|
} catch ( IfcException& e ) {
|
2017-06-05 17:26:58 +02:00
|
|
|
Logger::Message(Logger::LOG_ERROR, e.what());
|
2012-03-31 09:54:15 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
} else {
|
2017-06-05 17:26:58 +02:00
|
|
|
attributes.push_back(new TokenArgument(next));
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
next = tokens->Next();
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2014-11-02 18:36:51 +00:00
|
|
|
IfcUtil::ArgumentType ArgumentList::type() const {
|
2016-11-08 17:24:08 +01:00
|
|
|
if (list.empty()) {
|
|
|
|
|
return IfcUtil::Argument_EMPTY_AGGREGATE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-02 18:36:51 +00:00
|
|
|
const IfcUtil::ArgumentType elem_type = list[0]->type();
|
|
|
|
|
if (elem_type == IfcUtil::Argument_INT) {
|
2015-04-07 15:06:56 +00:00
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_INT;
|
2014-11-02 18:36:51 +00:00
|
|
|
} else if (elem_type == IfcUtil::Argument_DOUBLE) {
|
2015-04-07 15:06:56 +00:00
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_DOUBLE;
|
2014-11-02 18:36:51 +00:00
|
|
|
} else if (elem_type == IfcUtil::Argument_STRING) {
|
2015-04-07 15:06:56 +00:00
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_STRING;
|
|
|
|
|
} else if (elem_type == IfcUtil::Argument_BINARY) {
|
|
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_BINARY;
|
|
|
|
|
} else if (elem_type == IfcUtil::Argument_ENTITY_INSTANCE) {
|
|
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE;
|
2015-06-16 12:58:07 +00:00
|
|
|
} else if (elem_type == IfcUtil::Argument_AGGREGATE_OF_INT) {
|
|
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT;
|
|
|
|
|
} else if (elem_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
|
|
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE;
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (elem_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
|
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE;
|
2016-11-08 17:24:08 +01:00
|
|
|
} else if (elem_type == IfcUtil::Argument_EMPTY_AGGREGATE) {
|
|
|
|
|
return IfcUtil::Argument_AGGREGATE_OF_EMPTY_AGGREGATE;
|
2014-11-02 18:36:51 +00:00
|
|
|
} else {
|
|
|
|
|
return IfcUtil::Argument_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-16 16:26:40 +00:00
|
|
|
void ArgumentList::push(Argument* l) {
|
2011-07-11 09:33:18 +00:00
|
|
|
list.push_back(l);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-07 15:06:56 +00:00
|
|
|
// templated helper function for reading arguments into a list
|
|
|
|
|
template<typename T>
|
2015-06-16 12:58:07 +00:00
|
|
|
std::vector<T> read_aggregate_as_vector(const std::vector<Argument*>& list) {
|
2015-04-07 15:06:56 +00:00
|
|
|
std::vector<T> return_value;
|
|
|
|
|
return_value.reserve(list.size());
|
|
|
|
|
std::vector<Argument*>::const_iterator it = list.begin();
|
|
|
|
|
for (; it != list.end(); ++it) {
|
|
|
|
|
return_value.push_back(**it);
|
|
|
|
|
}
|
|
|
|
|
return return_value;
|
|
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
template<typename T>
|
|
|
|
|
std::vector< std::vector<T> > read_aggregate_of_aggregate_as_vector2(const std::vector<Argument*>& list) {
|
|
|
|
|
std::vector< std::vector<T> > return_value;
|
|
|
|
|
return_value.reserve(list.size());
|
|
|
|
|
std::vector<Argument*>::const_iterator it = list.begin();
|
|
|
|
|
for (; it != list.end(); ++it) {
|
|
|
|
|
return_value.push_back(**it);
|
|
|
|
|
}
|
|
|
|
|
return return_value;
|
|
|
|
|
}
|
2015-04-07 15:06:56 +00:00
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
|
|
|
|
// Functions for casting the ArgumentList to other types
|
|
|
|
|
//
|
2012-03-13 11:56:52 +00:00
|
|
|
ArgumentList::operator std::vector<double>() const {
|
2015-06-16 12:58:07 +00:00
|
|
|
return read_aggregate_as_vector<double>(list);
|
2011-07-25 14:56:40 +00:00
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
ArgumentList::operator std::vector<int>() const {
|
2015-06-16 12:58:07 +00:00
|
|
|
return read_aggregate_as_vector<int>(list);
|
2011-07-25 14:56:40 +00:00
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
ArgumentList::operator std::vector<std::string>() const {
|
2015-06-16 12:58:07 +00:00
|
|
|
return read_aggregate_as_vector<std::string>(list);
|
2015-04-07 15:06:56 +00:00
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2015-04-07 15:06:56 +00:00
|
|
|
ArgumentList::operator std::vector<boost::dynamic_bitset<> >() const {
|
2015-06-16 12:58:07 +00:00
|
|
|
return read_aggregate_as_vector<boost::dynamic_bitset<> >(list);
|
2011-07-25 14:56:40 +00:00
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
ArgumentList::operator IfcEntityList::ptr() const {
|
|
|
|
|
IfcEntityList::ptr l ( new IfcEntityList() );
|
|
|
|
|
std::vector<Argument*>::const_iterator it;
|
2011-07-11 09:33:18 +00:00
|
|
|
for ( it = list.begin(); it != list.end(); ++ it ) {
|
|
|
|
|
// FIXME: account for $
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcUtil::IfcBaseClass* entity = **it;
|
2011-07-11 09:33:18 +00:00
|
|
|
l->push(entity);
|
|
|
|
|
}
|
|
|
|
|
return l;
|
|
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
|
|
|
|
ArgumentList::operator std::vector< std::vector<int> >() const {
|
|
|
|
|
return read_aggregate_of_aggregate_as_vector2<int>(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ArgumentList::operator std::vector< std::vector<double> >() const {
|
|
|
|
|
return read_aggregate_of_aggregate_as_vector2<double>(list);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
ArgumentList::operator IfcEntityListList::ptr() const {
|
|
|
|
|
IfcEntityListList::ptr l ( new IfcEntityListList() );
|
|
|
|
|
std::vector<Argument*>::const_iterator it;
|
|
|
|
|
for ( it = list.begin(); it != list.end(); ++ it ) {
|
|
|
|
|
const Argument* arg = *it;
|
|
|
|
|
const ArgumentList* arg_list;
|
2015-11-21 23:05:28 +02:00
|
|
|
if ((arg_list = dynamic_cast<const ArgumentList*>(arg)) != 0) {
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcEntityList::ptr e = *arg_list;
|
|
|
|
|
l->push(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return l;
|
|
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2015-01-10 22:13:52 +00:00
|
|
|
unsigned int ArgumentList::size() const { return (unsigned int) list.size(); }
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2014-05-04 14:42:55 +00:00
|
|
|
Argument* ArgumentList::operator [] (unsigned int i) const {
|
2015-01-16 16:26:40 +00:00
|
|
|
if ( i >= list.size() ) {
|
2015-06-17 11:04:28 +00:00
|
|
|
throw IfcAttributeOutOfRangeException("Argument index out of range");
|
2015-01-16 16:26:40 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
return list[i];
|
|
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2015-01-16 16:26:40 +00:00
|
|
|
void ArgumentList::set(unsigned int i, Argument* argument) {
|
|
|
|
|
while (size() < i) {
|
2016-06-09 22:25:50 +06:00
|
|
|
push(new NullArgument());
|
2015-01-16 16:26:40 +00:00
|
|
|
}
|
|
|
|
|
if (i < size()) {
|
|
|
|
|
delete list[i];
|
|
|
|
|
list[i] = argument;
|
|
|
|
|
} else {
|
|
|
|
|
list.push_back(argument);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2012-03-13 11:56:52 +00:00
|
|
|
std::string ArgumentList::toString(bool upper) const {
|
2011-07-11 09:33:18 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "(";
|
2014-05-04 14:42:55 +00:00
|
|
|
for( std::vector<Argument*>::const_iterator it = list.begin(); it != list.end(); it ++ ) {
|
2011-07-11 09:33:18 +00:00
|
|
|
if ( it != list.begin() ) ss << ",";
|
2012-03-13 11:56:52 +00:00
|
|
|
ss << (*it)->toString(upper);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
|
|
|
|
ss << ")";
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
bool ArgumentList::isNull() const { return false; }
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2011-09-03 13:58:59 +00:00
|
|
|
ArgumentList::~ArgumentList() {
|
2014-05-04 14:42:55 +00:00
|
|
|
for( std::vector<Argument*>::iterator it = list.begin(); it != list.end(); it ++ ) {
|
2011-09-03 13:58:59 +00:00
|
|
|
delete (*it);
|
|
|
|
|
}
|
|
|
|
|
list.clear();
|
|
|
|
|
}
|
2011-05-08 11:04:32 +00:00
|
|
|
|
2015-06-16 12:58:07 +00:00
|
|
|
|
2014-11-02 18:36:51 +00:00
|
|
|
IfcUtil::ArgumentType TokenArgument::type() const {
|
|
|
|
|
if (TokenFunc::isInt(token)) {
|
|
|
|
|
return IfcUtil::Argument_INT;
|
|
|
|
|
} else if (TokenFunc::isBool(token)) {
|
|
|
|
|
return IfcUtil::Argument_BOOL;
|
|
|
|
|
} else if (TokenFunc::isFloat(token)) {
|
|
|
|
|
return IfcUtil::Argument_DOUBLE;
|
|
|
|
|
} else if (TokenFunc::isString(token)) {
|
|
|
|
|
return IfcUtil::Argument_STRING;
|
|
|
|
|
} else if (TokenFunc::isEnumeration(token)) {
|
|
|
|
|
return IfcUtil::Argument_ENUMERATION;
|
|
|
|
|
} else if (TokenFunc::isIdentifier(token)) {
|
2015-04-07 15:06:56 +00:00
|
|
|
return IfcUtil::Argument_ENTITY_INSTANCE;
|
|
|
|
|
} else if (TokenFunc::isBinary(token)) {
|
|
|
|
|
return IfcUtil::Argument_BINARY;
|
2015-03-12 17:54:52 +00:00
|
|
|
} else if (TokenFunc::isOperator(token, '$')) {
|
|
|
|
|
return IfcUtil::Argument_NULL;
|
|
|
|
|
} else if (TokenFunc::isOperator(token, '*')) {
|
|
|
|
|
return IfcUtil::Argument_DERIVED;
|
2014-11-02 18:36:51 +00:00
|
|
|
} else {
|
|
|
|
|
return IfcUtil::Argument_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
|
|
|
|
// Functions for casting the TokenArgument to other types
|
|
|
|
|
//
|
|
|
|
|
TokenArgument::operator int() const { return TokenFunc::asInt(token); }
|
|
|
|
|
TokenArgument::operator bool() const { return TokenFunc::asBool(token); }
|
2012-03-13 11:56:52 +00:00
|
|
|
TokenArgument::operator double() const { return TokenFunc::asFloat(token); }
|
2011-07-11 09:33:18 +00:00
|
|
|
TokenArgument::operator std::string() const { return TokenFunc::asString(token); }
|
2015-04-07 15:06:56 +00:00
|
|
|
TokenArgument::operator boost::dynamic_bitset<>() const { return TokenFunc::asBinary(token); }
|
2016-06-09 22:25:50 +06:00
|
|
|
TokenArgument::operator IfcUtil::IfcBaseClass*() const { return token.lexer->file->entityById(TokenFunc::asIdentifier(token)); }
|
2015-01-10 22:13:52 +00:00
|
|
|
unsigned int TokenArgument::size() const { return 1; }
|
2015-11-23 15:52:12 +02:00
|
|
|
Argument* TokenArgument::operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of attributes"); }
|
2012-10-09 19:54:35 +00:00
|
|
|
std::string TokenArgument::toString(bool upper) const {
|
|
|
|
|
if ( upper && TokenFunc::isString(token) ) {
|
|
|
|
|
return IfcWrite::IfcCharacterEncoder(TokenFunc::asString(token));
|
|
|
|
|
} else {
|
|
|
|
|
return TokenFunc::toString(token);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-25 14:56:40 +00:00
|
|
|
bool TokenArgument::isNull() const { return TokenFunc::isOperator(token,'$'); }
|
2014-11-02 18:36:51 +00:00
|
|
|
|
|
|
|
|
IfcUtil::ArgumentType EntityArgument::type() const {
|
2015-04-07 15:06:56 +00:00
|
|
|
return IfcUtil::Argument_ENTITY_INSTANCE;
|
2014-11-02 18:36:51 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
|
|
|
|
// Functions for casting the EntityArgument to other types
|
|
|
|
|
//
|
2015-01-05 14:11:42 +00:00
|
|
|
EntityArgument::operator IfcUtil::IfcBaseClass*() const { return entity; }
|
2015-01-10 22:13:52 +00:00
|
|
|
unsigned int EntityArgument::size() const { return 1; }
|
2015-11-23 15:52:12 +02:00
|
|
|
Argument* EntityArgument::operator [] (unsigned int /*i*/) const { throw IfcException("Argument is not a list of arguments"); }
|
2012-03-13 11:56:52 +00:00
|
|
|
std::string EntityArgument::toString(bool upper) const {
|
2015-01-05 14:11:42 +00:00
|
|
|
return entity->entity->toString(upper);
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
2011-09-03 13:58:59 +00:00
|
|
|
//return entity->entity->toString(); }
|
2011-07-25 14:56:40 +00:00
|
|
|
bool EntityArgument::isNull() const { return false; }
|
2016-05-29 18:12:57 +06:00
|
|
|
EntityArgument::~EntityArgument() { delete entity->entity; delete entity;}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Reads an Entity from the list of Tokens at the specified offset in the file
|
|
|
|
|
//
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcEntityInstanceData* IfcParse::read(unsigned int i, IfcFile* f, boost::optional<unsigned> offset) {
|
|
|
|
|
if (offset) {
|
|
|
|
|
f->tokens->stream->Seek(*offset);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
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;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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");
|
2011-09-25 09:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Returns a string representation of the entity
|
|
|
|
|
// Note that this initializes the entity if it is not initialized
|
|
|
|
|
//
|
2017-06-05 17:26:58 +02:00
|
|
|
std::string IfcEntityInstanceData::toString(bool upper) const {
|
|
|
|
|
if (!initialized_) {
|
|
|
|
|
load_();
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-01-25 10:50:12 +00:00
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
std::stringstream ss;
|
2015-02-17 20:23:21 +00:00
|
|
|
ss.imbue(std::locale::classic());
|
|
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
std::string dt = IfcSchema::Type::ToString(type());
|
2015-01-25 10:50:12 +00:00
|
|
|
if (upper) {
|
2015-09-13 15:00:21 +02:00
|
|
|
boost::to_upper(dt);
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
2015-01-25 10:50:12 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
if (!IfcSchema::Type::IsSimple(type()) || id_ != 0) {
|
|
|
|
|
ss << "#" << id_ << "=";
|
2015-01-16 16:26:40 +00:00
|
|
|
}
|
2015-01-25 10:50:12 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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 << ")";
|
2015-01-25 10:50:12 +00:00
|
|
|
|
2011-05-08 11:04:32 +00:00
|
|
|
return ss.str();
|
|
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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();
|
|
|
|
|
}
|
2011-09-03 13:58:59 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
2015-01-10 22:13:52 +00:00
|
|
|
// Returns the entities of Entity type that have this entity in their ArgumentList
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcEntityList::ptr IfcEntityInstanceData::getInverse(IfcSchema::Type::Enum type, int attribute_index) {
|
|
|
|
|
return file->getInverse(id_, type, attribute_index);
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcFile::IfcFile()
|
|
|
|
|
: parsing_complete_(false)
|
2015-01-16 16:26:40 +00:00
|
|
|
, MaxId(0)
|
2016-05-15 15:47:21 +02:00
|
|
|
, tokens(0)
|
|
|
|
|
, stream(0)
|
2015-01-05 14:11:42 +00:00
|
|
|
{
|
2015-01-16 16:26:40 +00:00
|
|
|
setDefaultHeaderValues();
|
2012-08-11 13:24:08 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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) {
|
2017-06-15 14:12:03 +02:00
|
|
|
if (!initialized_) {
|
|
|
|
|
load_();
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-11 09:33:18 +00:00
|
|
|
//
|
|
|
|
|
// Parses the IFC file in fn
|
|
|
|
|
// Creates the maps
|
|
|
|
|
//
|
2012-08-11 13:24:08 +00:00
|
|
|
bool IfcFile::Init(const std::string& fn) {
|
|
|
|
|
return IfcFile::Init(new IfcSpfStream(fn));
|
2011-08-20 09:08:56 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool IfcFile::Init(std::istream& f, int len) {
|
|
|
|
|
return IfcFile::Init(new IfcSpfStream(f,len));
|
2011-08-20 09:08:56 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
bool IfcFile::Init(void* data, int len) {
|
|
|
|
|
return IfcFile::Init(new IfcSpfStream(data,len));
|
2011-10-27 16:13:29 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
bool IfcFile::Init(IfcParse::IfcSpfStream* s) {
|
2015-02-03 13:53:36 +00:00
|
|
|
// Initialize a "C" locale for locale-independent
|
|
|
|
|
// number parsing. See comment above on line 41.
|
|
|
|
|
init_locale();
|
|
|
|
|
|
2015-01-05 17:46:23 +00:00
|
|
|
stream = s;
|
|
|
|
|
if (!stream->valid) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tokens = new IfcSpfLexer(stream, this);
|
2017-06-05 17:26:58 +02:00
|
|
|
_header.file(this);
|
2015-01-05 17:46:23 +00:00
|
|
|
_header.tryRead();
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> schemas;
|
|
|
|
|
try {
|
|
|
|
|
schemas = _header.file_schema().schema_identifiers();
|
|
|
|
|
} catch (...) {}
|
|
|
|
|
if (schemas.size() != 1 || schemas[0] != IfcSchema::Identifier) {
|
2015-02-06 12:59:36 +00:00
|
|
|
Logger::Message(Logger::LOG_ERROR, std::string("File schema encountered different from expected '") + IfcSchema::Identifier + "'");
|
2015-01-05 17:46:23 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
boost::circular_buffer<Token> token_stream(3);
|
2015-01-05 17:46:23 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcEntityInstanceData* data;
|
|
|
|
|
IfcUtil::IfcBaseClass* instance = 0;
|
|
|
|
|
|
|
|
|
|
unsigned current_id = 0;
|
|
|
|
|
int progress = 0;
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Status("Scanning file...");
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
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;
|
2011-10-13 11:25:59 +00:00
|
|
|
try {
|
2017-06-05 17:26:58 +02:00
|
|
|
entity_type = IfcSchema::Type::FromString(TokenFunc::asStringRef(token_stream[2]));
|
2015-06-17 11:04:28 +00:00
|
|
|
} catch (const IfcException& ex) {
|
2017-06-05 17:26:58 +02:00
|
|
|
Logger::Message(Logger::LOG_ERROR, ex.what());
|
2017-06-14 12:42:38 +02:00
|
|
|
goto advance;
|
2017-06-05 17:26:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data = new IfcEntityInstanceData(entity_type, this, current_id, token_stream[2].startPos);
|
|
|
|
|
instance = IfcSchema::SchemaEntity(data);
|
|
|
|
|
|
2017-05-23 20:06:35 +03:00
|
|
|
/// @todo Printing to stdout in a library class feels weird. Maybe move the progress prints to the client code?
|
2012-08-11 13:24:08 +00:00
|
|
|
// Update the status after every 1000 instances parsed
|
2017-06-05 17:26:58 +02:00
|
|
|
if (!((++progress) % 1000)) {
|
|
|
|
|
std::stringstream ss; ss << "\r#" << current_id;
|
2012-10-19 08:20:43 +00:00
|
|
|
Logger::Status(ss.str(), false);
|
2012-08-11 13:24:08 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
if (instance->is(IfcSchema::Type::IfcRoot)) {
|
|
|
|
|
IfcSchema::IfcRoot* ifc_root = (IfcSchema::IfcRoot*) instance;
|
2012-03-13 11:56:52 +00:00
|
|
|
try {
|
|
|
|
|
const std::string guid = ifc_root->GlobalId();
|
|
|
|
|
if ( byguid.find(guid) != byguid.end() ) {
|
|
|
|
|
std::stringstream ss;
|
2015-10-05 13:08:24 +02:00
|
|
|
ss << "Instance encountered with non-unique GlobalId " << guid;
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,ss.str());
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
|
|
|
|
byguid[guid] = ifc_root;
|
2015-06-17 11:04:28 +00:00
|
|
|
} catch (const IfcException& ex) {
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_ERROR,ex.what());
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-11-04 12:02:28 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcSchema::Type::Enum ty = instance->type();
|
2016-03-18 11:14:14 +01:00
|
|
|
for (;;) {
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr instances_by_type = entitiesByType(ty);
|
2014-11-04 12:02:28 +00:00
|
|
|
if (!instances_by_type) {
|
|
|
|
|
instances_by_type = IfcEntityList::ptr(new IfcEntityList());
|
|
|
|
|
bytype[ty] = instances_by_type;
|
2011-08-24 12:21:07 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
instances_by_type->push(instance);
|
2016-03-18 11:14:14 +01:00
|
|
|
boost::optional<IfcSchema::Type::Enum> pt = IfcSchema::Type::Parent(ty);
|
|
|
|
|
if (pt) {
|
|
|
|
|
ty = *pt;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-04 12:02:28 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
if (byid.find(current_id) != byid.end()) {
|
2012-02-04 15:10:17 +00:00
|
|
|
std::stringstream ss;
|
2017-06-05 17:26:58 +02:00
|
|
|
ss << "Overwriting instance with name #" << current_id;
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,ss.str());
|
2012-02-04 15:10:17 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
byid[current_id] = instance;
|
2014-11-04 12:02:28 +00:00
|
|
|
|
2017-06-05 17:26:58 +02:00
|
|
|
MaxId = (std::max)(MaxId, current_id);
|
|
|
|
|
} else if (token_stream[0].type == IfcParse::Token_IDENTIFIER && instance) {
|
|
|
|
|
register_inverse(current_id, token_stream[0]);
|
2012-03-13 11:56:52 +00:00
|
|
|
}
|
2014-11-04 12:02:28 +00:00
|
|
|
|
2017-06-14 12:42:38 +02:00
|
|
|
advance:
|
2017-06-05 17:26:58 +02:00
|
|
|
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");
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
if (next_token.type == Token_NONE) break;
|
|
|
|
|
|
|
|
|
|
token_stream.push_back(next_token);
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Status("\rDone scanning file ");
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
parsing_complete_ = true;
|
|
|
|
|
|
2011-07-25 14:56:40 +00:00
|
|
|
return true;
|
2011-07-11 09:33:18 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
void IfcFile::traverse(IfcUtil::IfcBaseClass* instance, std::set<IfcUtil::IfcBaseClass*>& visited, IfcEntityList::ptr list, int level, int max_level) {
|
|
|
|
|
if (visited.find(instance) != visited.end()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
visited.insert(instance);
|
|
|
|
|
list->push(instance);
|
|
|
|
|
|
|
|
|
|
if (level >= max_level && max_level > 0) return;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < instance->getArgumentCount(); ++i) {
|
|
|
|
|
Argument* arg = instance->getArgument(i);
|
|
|
|
|
|
2015-04-07 15:06:56 +00:00
|
|
|
if (arg->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
|
2015-02-17 19:48:41 +00:00
|
|
|
traverse(*arg, visited, list, level + 1, max_level);
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcEntityList::ptr entity_list_attribute = *arg;
|
|
|
|
|
for (IfcEntityList::it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
|
|
|
|
|
traverse(*it, visited, list, level + 1, max_level);
|
|
|
|
|
}
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcEntityListList::ptr entity_list_attribute = *arg;
|
|
|
|
|
for (IfcEntityListList::outer_it it = entity_list_attribute->begin(); it != entity_list_attribute->end(); ++it) {
|
|
|
|
|
for (IfcEntityListList::inner_it jt = it->begin(); jt != it->end(); ++jt) {
|
|
|
|
|
traverse(*jt, visited, list, level + 1, max_level);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IfcEntityList::ptr IfcFile::traverse(IfcUtil::IfcBaseClass* instance, int max_level) {
|
|
|
|
|
std::set<IfcUtil::IfcBaseClass*> visited;
|
|
|
|
|
IfcEntityList::ptr return_value(new IfcEntityList);
|
|
|
|
|
traverse(instance, visited, return_value, 0, max_level);
|
|
|
|
|
return return_value;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
void IfcFile::addEntities(IfcEntityList::ptr es) {
|
2012-08-11 13:24:08 +00:00
|
|
|
for( IfcEntityList::it i = es->begin(); i != es->end(); ++ i ) {
|
2015-02-17 19:55:27 +00:00
|
|
|
addEntity(*i);
|
2012-08-11 13:24:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-02-17 19:55:27 +00:00
|
|
|
IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity) {
|
2015-02-17 19:48:41 +00:00
|
|
|
// If this instance has been inserted before, return
|
|
|
|
|
// a reference to the copy that was created from it.
|
2015-11-21 23:05:28 +02:00
|
|
|
entity_entity_map_t::iterator mit = entity_file_map.find(entity);
|
|
|
|
|
if (mit != entity_file_map.end()) {
|
|
|
|
|
return mit->second;
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Obtain all forward references by a depth-first
|
|
|
|
|
// traversal and add them to the file.
|
2015-02-17 22:02:06 +00:00
|
|
|
try {
|
|
|
|
|
IfcEntityList::ptr entity_attributes = traverse(entity, 1);
|
|
|
|
|
for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) {
|
|
|
|
|
if (*it != entity) {
|
|
|
|
|
entity_file_map.insert(entity_entity_map_t::value_type(*it, addEntity(*it)));
|
|
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
2015-03-12 17:54:52 +00:00
|
|
|
} catch (...) {
|
|
|
|
|
Logger::Message(Logger::LOG_ERROR, "Failed to visit forward references of", entity->entity);
|
|
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
// See whether the instance is already part of a file
|
|
|
|
|
if (entity->entity->file != 0) {
|
|
|
|
|
if (entity->entity->file == this) {
|
|
|
|
|
// If it is part of this file
|
|
|
|
|
// nothing needs to be done.
|
|
|
|
|
return entity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// An instance is being added from another file. A copy of the
|
|
|
|
|
// 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;
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcEntityInstanceData* we = new IfcEntityInstanceData(*entity->entity);
|
|
|
|
|
entity = IfcSchema::SchemaEntity(we);
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
// In case an entity is added that contains geometry, the unit
|
|
|
|
|
// information needs to be accounted for for IfcLengthMeasures.
|
2016-07-15 06:49:32 +03:00
|
|
|
double conversion_factor = std::numeric_limits<double>::quiet_NaN();
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < we->getArgumentCount(); ++i) {
|
|
|
|
|
Argument* attr = we->getArgument(i);
|
|
|
|
|
IfcUtil::ArgumentType attr_type = attr->type();
|
2015-04-07 15:06:56 +00:00
|
|
|
if (attr_type == IfcUtil::Argument_ENTITY_INSTANCE) {
|
2015-03-12 17:54:52 +00:00
|
|
|
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");
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(eit->second);
|
|
|
|
|
we->setArgument(i, copy);
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcEntityList::ptr instances = *attr;
|
|
|
|
|
IfcEntityList::ptr new_instances(new IfcEntityList);
|
|
|
|
|
for (IfcEntityList::it it = instances->begin(); it != instances->end(); ++it) {
|
2015-03-12 17:54:52 +00:00
|
|
|
entity_entity_map_t::const_iterator eit = entity_file_map.find(*it);
|
|
|
|
|
if (eit == entity_file_map.end()) throw IfcParse::IfcException("Unable to map instance to file");
|
|
|
|
|
new_instances->push(eit->second);
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(new_instances);
|
|
|
|
|
we->setArgument(i, copy);
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcEntityListList::ptr instances = *attr;
|
|
|
|
|
IfcEntityListList::ptr new_instances(new IfcEntityListList);
|
|
|
|
|
for (IfcEntityListList::outer_it it = instances->begin(); it != instances->end(); ++it) {
|
|
|
|
|
std::vector<IfcUtil::IfcBaseClass*> list;
|
|
|
|
|
for (IfcEntityListList::inner_it jt = it->begin(); jt != it->end(); ++jt) {
|
2015-03-12 17:54:52 +00:00
|
|
|
entity_entity_map_t::const_iterator eit = entity_file_map.find(*jt);
|
|
|
|
|
if (eit == entity_file_map.end()) throw IfcParse::IfcException("Unable to map instance to file");
|
|
|
|
|
list.push_back(eit->second);
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
new_instances->push(list);
|
|
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(new_instances);
|
|
|
|
|
we->setArgument(i, copy);
|
|
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
} else if (entity->getArgumentEntity(i) == IfcSchema::Type::IfcLengthMeasure ||
|
|
|
|
|
entity->getArgumentEntity(i) == IfcSchema::Type::IfcPositiveLengthMeasure)
|
|
|
|
|
{
|
2016-07-15 06:49:32 +03:00
|
|
|
if (boost::math::isnan(conversion_factor)) {
|
2015-02-17 19:48:41 +00:00
|
|
|
conversion_factor = other_file->getUnit(IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT).second /
|
|
|
|
|
getUnit(IfcSchema::IfcUnitEnum::IfcUnit_LENGTHUNIT).second;
|
|
|
|
|
}
|
|
|
|
|
if (attr_type == IfcUtil::Argument_DOUBLE) {
|
|
|
|
|
double v = *attr;
|
2016-07-15 06:49:32 +03:00
|
|
|
v *= conversion_factor;
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(v);
|
|
|
|
|
we->setArgument(i, copy);
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (attr_type == IfcUtil::Argument_AGGREGATE_OF_DOUBLE) {
|
2015-02-17 19:48:41 +00:00
|
|
|
std::vector<double> v = *attr;
|
|
|
|
|
for (std::vector<double>::iterator it = v.begin(); it != v.end(); ++it) {
|
2016-07-15 06:49:32 +03:00
|
|
|
(*it) *= conversion_factor;
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(v);
|
|
|
|
|
we->setArgument(i, copy);
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A new entity instance name is generated and
|
|
|
|
|
// the instance is pointed to this file.
|
|
|
|
|
we->file = this;
|
2017-06-05 17:26:58 +02:00
|
|
|
we->set_id(FreshId());
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For subtypes of IfcRoot, the GUID mapping needs to be updated.
|
|
|
|
|
if (entity->is(IfcSchema::Type::IfcRoot)) {
|
2014-05-04 14:42:55 +00:00
|
|
|
IfcSchema::IfcRoot* ifc_root = (IfcSchema::IfcRoot*) entity;
|
2012-07-18 19:32:58 +00:00
|
|
|
try {
|
|
|
|
|
const std::string guid = ifc_root->GlobalId();
|
|
|
|
|
if ( byguid.find(guid) != byguid.end() ) {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "Overwriting entity with guid " << guid;
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING,ss.str());
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
|
|
|
|
byguid[guid] = ifc_root;
|
2015-06-17 11:04:28 +00:00
|
|
|
} catch (const IfcException& ex) {
|
2012-08-11 13:24:08 +00:00
|
|
|
Logger::Message(Logger::LOG_ERROR,ex.what());
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-11-04 12:02:28 +00:00
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
// The mapping by entity type is updated.
|
2014-02-17 22:13:55 +00:00
|
|
|
IfcSchema::Type::Enum ty = entity->type();
|
2016-03-18 11:14:14 +01:00
|
|
|
for (;;) {
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr instances_by_type = entitiesByType(ty);
|
2014-11-04 12:02:28 +00:00
|
|
|
if (!instances_by_type) {
|
|
|
|
|
instances_by_type = IfcEntityList::ptr(new IfcEntityList());
|
|
|
|
|
bytype[ty] = instances_by_type;
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
2014-11-04 12:02:28 +00:00
|
|
|
instances_by_type->push(entity);
|
2016-03-18 11:14:14 +01:00
|
|
|
boost::optional<IfcSchema::Type::Enum> pt = IfcSchema::Type::Parent(ty);
|
|
|
|
|
if (pt) {
|
|
|
|
|
ty = *pt;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-04 12:02:28 +00:00
|
|
|
|
2012-07-18 19:32:58 +00:00
|
|
|
int new_id = -1;
|
2017-06-05 17:26:58 +02:00
|
|
|
if (!entity->entity->file) {
|
2015-02-17 19:48:41 +00:00
|
|
|
// For newly created entities ensure a valid ENTITY_INSTANCE_NAME is set
|
|
|
|
|
entity->entity->file = this;
|
2017-06-05 17:26:58 +02:00
|
|
|
new_id = entity->entity->set_id();
|
2012-07-18 19:32:58 +00:00
|
|
|
} else {
|
|
|
|
|
new_id = entity->entity->id();
|
|
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
if (byid.find(new_id) != byid.end()) {
|
|
|
|
|
// This should not happen
|
2012-07-18 19:32:58 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "Overwriting entity with id " << new_id;
|
2015-02-17 19:48:41 +00:00
|
|
|
Logger::Message(Logger::LOG_WARNING, ss.str());
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
// The mapping by entity instance name is updated.
|
|
|
|
|
byid[new_id] = entity;
|
2014-11-02 18:36:51 +00:00
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
// The mapping by reference is updated.
|
2015-02-17 22:02:06 +00:00
|
|
|
IfcEntityList::ptr entity_attributes(new IfcEntityList);
|
|
|
|
|
try {
|
|
|
|
|
entity_attributes = traverse(entity, 1);
|
|
|
|
|
} catch (...) {}
|
2015-02-17 19:48:41 +00:00
|
|
|
for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) {
|
|
|
|
|
IfcUtil::IfcBaseClass* entity_attribute = *it;
|
2015-02-19 14:42:19 +00:00
|
|
|
if (*it == entity) continue;
|
2015-02-17 19:48:41 +00:00
|
|
|
try {
|
|
|
|
|
if (!IfcSchema::Type::IsSimple(entity_attribute->type())) {
|
|
|
|
|
unsigned entity_attribute_id = entity_attribute->entity->id();
|
2017-06-05 17:26:58 +02:00
|
|
|
byref[entity_attribute_id].push_back(entity->entity->id());
|
2014-11-02 18:36:51 +00:00
|
|
|
}
|
2015-06-17 11:04:28 +00:00
|
|
|
} catch (const IfcParse::IfcException&) {}
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
2014-11-02 18:36:51 +00:00
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
return entity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
|
|
|
|
|
const unsigned id = entity->entity->id();
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcUtil::IfcBaseClass* file_entity = entityById(id);
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
// TODO: Create a set of weak relations. Inverse relations that do not dictate an
|
|
|
|
|
// instance to be retained. For example: when deleting an IfcRepresentation, the
|
|
|
|
|
// individual IfcRepresentationItems can not be deleted if an IfcStyledItem is
|
|
|
|
|
// related. Hence, the IfcRepresentationItem::StyledByItem relation could be
|
|
|
|
|
// characterized as weak.
|
|
|
|
|
std::set<IfcSchema::Type::Enum> weak_roots;
|
|
|
|
|
|
|
|
|
|
if (entity != file_entity) {
|
|
|
|
|
throw IfcParse::IfcException("Instance not part of this file");
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr references = entitiesByReference(id);
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
// Alter entity instances with INVERSE relations to the entity being
|
|
|
|
|
// deleted. This is necessary to maintain a valid IFC file, because
|
|
|
|
|
// dangling references to it's entities name should be removed. At this
|
|
|
|
|
// moment, inversely related instances affected by the removal of the
|
|
|
|
|
// entity being deleted are not deleted themselves.
|
|
|
|
|
if (references) {
|
2015-11-21 23:05:28 +02:00
|
|
|
for (IfcEntityList::it iit = references->begin(); iit != references->end(); ++iit) {
|
|
|
|
|
IfcUtil::IfcBaseEntity* related_instance = (IfcUtil::IfcBaseEntity*) *iit;
|
2015-02-17 19:48:41 +00:00
|
|
|
for (unsigned i = 0; i < related_instance->getArgumentCount(); ++i) {
|
|
|
|
|
Argument* attr = related_instance->getArgument(i);
|
|
|
|
|
if (attr->isNull()) continue;
|
|
|
|
|
|
|
|
|
|
IfcUtil::ArgumentType attr_type = related_instance->getArgumentType(i);
|
|
|
|
|
switch(attr_type) {
|
2015-04-07 15:06:56 +00:00
|
|
|
case IfcUtil::Argument_ENTITY_INSTANCE: {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcUtil::IfcBaseClass* instance_attribute = *attr;
|
|
|
|
|
if (instance_attribute == entity) {
|
2017-06-05 17:26:58 +02:00
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(boost::blank());
|
|
|
|
|
related_instance->entity->setArgument(i, copy);
|
2015-02-17 19:48:41 +00:00
|
|
|
} }
|
|
|
|
|
break;
|
2015-04-07 15:06:56 +00:00
|
|
|
case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcEntityList::ptr instance_list = *attr;
|
|
|
|
|
if (instance_list->contains(entity)) {
|
|
|
|
|
instance_list->remove(entity);
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(instance_list);
|
|
|
|
|
related_instance->entity->setArgument(i, copy);
|
2015-02-17 19:48:41 +00:00
|
|
|
} }
|
|
|
|
|
break;
|
2015-04-07 15:06:56 +00:00
|
|
|
case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: {
|
2015-02-17 19:48:41 +00:00
|
|
|
IfcEntityListList::ptr instance_list_list = *attr;
|
|
|
|
|
if (instance_list_list->contains(entity)) {
|
|
|
|
|
IfcEntityListList::ptr new_list(new IfcEntityListList);
|
|
|
|
|
for (IfcEntityListList::outer_it it = instance_list_list->begin(); it != instance_list_list->end(); ++it) {
|
|
|
|
|
std::vector<IfcUtil::IfcBaseClass*> instances = *it;
|
2015-02-17 21:24:18 +00:00
|
|
|
std::vector<IfcUtil::IfcBaseClass*>::iterator jt;
|
2015-02-17 19:48:41 +00:00
|
|
|
while ((jt = std::find(instances.begin(), instances.end(), entity)) != instances.end()) {
|
|
|
|
|
instances.erase(jt);
|
|
|
|
|
}
|
|
|
|
|
new_list->push(instances);
|
2014-11-27 09:22:58 +00:00
|
|
|
}
|
2017-06-05 17:26:58 +02:00
|
|
|
|
|
|
|
|
IfcWrite::IfcWriteArgument* copy = new IfcWrite::IfcWriteArgument();
|
|
|
|
|
copy->set(new_list);
|
|
|
|
|
related_instance->entity->setArgument(i, copy);
|
2015-02-17 19:48:41 +00:00
|
|
|
} }
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
2014-05-05 16:17:28 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
2014-05-05 16:17:28 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
byref.erase(byref.find(id));
|
2014-05-05 16:17:28 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
|
|
|
|
IfcEntityList::ptr entity_attributes = traverse(entity, 1);
|
|
|
|
|
for (IfcEntityList::it it = entity_attributes->begin(); it != entity_attributes->end(); ++it) {
|
|
|
|
|
IfcUtil::IfcBaseClass* entity_attribute = *it;
|
|
|
|
|
if (entity_attribute == entity) continue;
|
2017-04-25 16:37:50 +02:00
|
|
|
if (entity_attribute->entity->id() != 0) {
|
|
|
|
|
// Do not update inverses for simple types.
|
|
|
|
|
const IfcEntityList::ptr attribute_inverses = entitiesByReference(entity_attribute->entity->id());
|
|
|
|
|
|
|
|
|
|
if (attribute_inverses) {
|
|
|
|
|
attribute_inverses->remove(entity);
|
|
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entity->is(IfcSchema::Type::IfcRoot)) {
|
|
|
|
|
const std::string global_id = ((IfcSchema::IfcRoot*) entity)->GlobalId();
|
|
|
|
|
byguid.erase(byguid.find(global_id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
byid.erase(byid.find(id));
|
|
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr instances_of_same_type = entitiesByType(entity->type());
|
2015-02-17 19:48:41 +00:00
|
|
|
instances_of_same_type->remove(entity);
|
|
|
|
|
|
|
|
|
|
delete entity->entity;
|
|
|
|
|
delete entity;
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr IfcFile::entitiesByType(IfcSchema::Type::Enum t) {
|
2015-01-05 14:11:42 +00:00
|
|
|
entities_by_type_t::const_iterator it = bytype.find(t);
|
2014-05-04 14:42:55 +00:00
|
|
|
return (it == bytype.end()) ? IfcEntityList::ptr() : it->second;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr IfcFile::entitiesByType(const std::string& t) {
|
2015-09-13 15:00:21 +02:00
|
|
|
return entitiesByType(IfcSchema::Type::FromString(boost::to_upper_copy(t)));
|
2012-07-19 00:14:01 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr IfcFile::entitiesByReference(int t) {
|
2015-01-05 14:11:42 +00:00
|
|
|
entities_by_ref_t::const_iterator it = byref.find(t);
|
2017-06-05 17:26:58 +02:00
|
|
|
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;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcUtil::IfcBaseClass* IfcFile::entityById(int id) {
|
2015-01-05 14:11:42 +00:00
|
|
|
entity_by_id_t::const_iterator it = byid.find(id);
|
2015-02-17 19:48:41 +00:00
|
|
|
if (it == byid.end()) {
|
|
|
|
|
throw IfcException("Entity not found");
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2011-07-11 09:33:18 +00:00
|
|
|
return it->second;
|
2011-05-08 11:04:32 +00:00
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcSchema::IfcRoot* IfcFile::entityByGuid(const std::string& guid) {
|
2015-01-05 14:11:42 +00:00
|
|
|
entity_by_guid_t::const_iterator it = byguid.find(guid);
|
2012-03-13 11:56:52 +00:00
|
|
|
if ( it == byguid.end() ) {
|
|
|
|
|
throw IfcException("Entity not found");
|
|
|
|
|
} else {
|
|
|
|
|
return it->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-25 14:56:40 +00:00
|
|
|
|
2012-08-11 13:24:08 +00:00
|
|
|
// FIXME: Test destructor to delete entity and arg allocations
|
|
|
|
|
IfcFile::~IfcFile() {
|
2015-01-05 14:11:42 +00:00
|
|
|
for( entity_by_id_t::const_iterator it = byid.begin(); it != byid.end(); ++ it ) {
|
2011-09-03 13:58:59 +00:00
|
|
|
delete it->second->entity;
|
|
|
|
|
delete it->second;
|
|
|
|
|
}
|
2015-01-05 14:11:42 +00:00
|
|
|
delete stream;
|
2011-09-03 13:58:59 +00:00
|
|
|
delete tokens;
|
2012-08-11 13:24:08 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-05 14:11:42 +00:00
|
|
|
IfcFile::entity_by_id_t::const_iterator IfcFile::begin() const {
|
2012-03-16 15:21:52 +00:00
|
|
|
return byid.begin();
|
|
|
|
|
}
|
2015-02-17 19:48:41 +00:00
|
|
|
|
2015-01-05 14:11:42 +00:00
|
|
|
IfcFile::entity_by_id_t::const_iterator IfcFile::end() const {
|
2012-03-16 15:21:52 +00:00
|
|
|
return byid.end();
|
|
|
|
|
}
|
2012-08-11 13:24:08 +00:00
|
|
|
|
|
|
|
|
std::ostream& operator<< (std::ostream& os, const IfcParse::IfcFile& f) {
|
2015-01-16 16:26:40 +00:00
|
|
|
f.header().write(os);
|
2012-07-18 19:32:58 +00:00
|
|
|
|
2015-01-05 14:11:42 +00:00
|
|
|
for ( IfcFile::entity_by_id_t::const_iterator it = f.begin(); it != f.end(); ++ it ) {
|
2014-05-04 14:42:55 +00:00
|
|
|
const IfcUtil::IfcBaseClass* e = it->second;
|
2015-01-25 10:50:12 +00:00
|
|
|
if (!IfcSchema::Type::IsSimple(e->type())) {
|
|
|
|
|
os << e->entity->toString(true) << ";" << std::endl;
|
|
|
|
|
}
|
2012-07-18 19:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
os << "ENDSEC;" << std::endl;
|
2012-08-11 13:24:08 +00:00
|
|
|
os << "END-ISO-10303-21;" << std::endl;
|
|
|
|
|
|
|
|
|
|
return os;
|
|
|
|
|
}
|
2012-11-17 15:19:38 +00:00
|
|
|
|
2015-01-16 16:26:40 +00:00
|
|
|
std::string IfcFile::createTimestamp() const {
|
2012-11-17 15:19:38 +00:00
|
|
|
char buf[255];
|
2015-01-16 16:26:40 +00:00
|
|
|
|
2012-11-17 15:19:38 +00:00
|
|
|
time_t t;
|
|
|
|
|
time(&t);
|
2015-01-16 16:26:40 +00:00
|
|
|
|
|
|
|
|
struct tm* ti = localtime (&t);
|
|
|
|
|
|
|
|
|
|
std::string result = "";
|
2012-11-17 15:19:38 +00:00
|
|
|
if (strftime(buf,255,"%Y-%m-%dT%H:%M:%S",ti)) {
|
2015-01-16 16:26:40 +00:00
|
|
|
result = std::string(buf);
|
2012-11-17 15:19:38 +00:00
|
|
|
}
|
2015-01-16 16:26:40 +00:00
|
|
|
|
|
|
|
|
return result;
|
2015-01-10 22:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IfcEntityList::ptr IfcFile::getInverse(int instance_id, IfcSchema::Type::Enum type, int attribute_index) {
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcUtil::IfcBaseClass* instance = entityById(instance_id);
|
2015-01-10 22:13:52 +00:00
|
|
|
|
|
|
|
|
IfcEntityList::ptr l = IfcEntityList::ptr(new IfcEntityList);
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcEntityList::ptr all = entitiesByReference(instance_id);
|
2015-01-10 22:13:52 +00:00
|
|
|
if (!all) return l;
|
|
|
|
|
|
|
|
|
|
for(IfcEntityList::it it = all->begin(); it != all->end(); ++it) {
|
2015-02-17 19:48:41 +00:00
|
|
|
bool valid = type == IfcSchema::Type::UNDEFINED || (*it)->is(type);
|
2015-01-10 22:13:52 +00:00
|
|
|
if (valid && attribute_index >= 0) {
|
|
|
|
|
Argument* arg = (*it)->entity->getArgument(attribute_index);
|
2015-04-07 15:06:56 +00:00
|
|
|
if (arg->type() == IfcUtil::Argument_ENTITY_INSTANCE) {
|
2015-01-10 22:13:52 +00:00
|
|
|
valid = instance == *arg;
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) {
|
2015-01-10 22:13:52 +00:00
|
|
|
IfcEntityList::ptr li = *arg;
|
|
|
|
|
valid = li->contains(instance);
|
2015-04-07 15:06:56 +00:00
|
|
|
} else if (arg->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) {
|
2015-01-10 22:13:52 +00:00
|
|
|
IfcEntityListList::ptr li = *arg;
|
|
|
|
|
valid = li->contains(instance);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (valid) {
|
|
|
|
|
l->push(*it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return l;
|
2015-01-16 16:26:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IfcFile::setDefaultHeaderValues() {
|
|
|
|
|
const std::string empty_string = "";
|
|
|
|
|
std::vector<std::string> file_description, schema_identifiers, empty_vector;
|
|
|
|
|
|
|
|
|
|
file_description.push_back("ViewDefinition [CoordinationView]");
|
|
|
|
|
schema_identifiers.push_back(IfcSchema::Identifier);
|
|
|
|
|
|
|
|
|
|
header().file_description().description(file_description);
|
|
|
|
|
header().file_description().implementation_level("2;1");
|
|
|
|
|
|
|
|
|
|
header().file_name().name(empty_string);
|
|
|
|
|
header().file_name().time_stamp(createTimestamp());
|
|
|
|
|
header().file_name().author(empty_vector);
|
|
|
|
|
header().file_name().organization(empty_vector);
|
|
|
|
|
header().file_name().preprocessor_version("IfcOpenShell " IFCOPENSHELL_VERSION);
|
|
|
|
|
header().file_name().originating_system("IfcOpenShell " IFCOPENSHELL_VERSION);
|
|
|
|
|
header().file_name().authorization(empty_string);
|
|
|
|
|
|
|
|
|
|
header().file_schema().schema_identifiers(schema_identifiers);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 19:48:41 +00:00
|
|
|
std::pair<IfcSchema::IfcNamedUnit*, double> IfcFile::getUnit(IfcSchema::IfcUnitEnum::IfcUnitEnum type) {
|
|
|
|
|
std::pair<IfcSchema::IfcNamedUnit*, double> return_value((IfcSchema::IfcNamedUnit*)0, 1.);
|
2015-02-17 20:07:09 +00:00
|
|
|
IfcSchema::IfcProject::list::ptr projects = entitiesByType<IfcSchema::IfcProject>();
|
2015-02-17 19:48:41 +00:00
|
|
|
if (projects->size() == 1) {
|
|
|
|
|
IfcSchema::IfcProject* project = *projects->begin();
|
|
|
|
|
IfcEntityList::ptr units = project->UnitsInContext()->Units();
|
|
|
|
|
for (IfcEntityList::it it = units->begin(); it != units->end(); ++it) {
|
|
|
|
|
IfcSchema::IfcUnit* unit = *it;
|
|
|
|
|
if (unit->is(IfcSchema::Type::IfcNamedUnit)) {
|
|
|
|
|
IfcSchema::IfcNamedUnit* named_unit = (IfcSchema::IfcNamedUnit*) unit;
|
|
|
|
|
if (named_unit->UnitType() != type) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-11-21 23:05:28 +02:00
|
|
|
IfcSchema::IfcSIUnit* siunit = 0;
|
2015-02-17 19:48:41 +00:00
|
|
|
if (named_unit->is(IfcSchema::Type::IfcConversionBasedUnit)) {
|
|
|
|
|
IfcSchema::IfcConversionBasedUnit* u = (IfcSchema::IfcConversionBasedUnit*)named_unit;
|
|
|
|
|
IfcSchema::IfcMeasureWithUnit* mu = u->ConversionFactor();
|
|
|
|
|
return_value.second *= static_cast<double>(*mu->ValueComponent()->entity->getArgument(0));
|
|
|
|
|
return_value.first = named_unit;
|
|
|
|
|
if (mu->UnitComponent()->is(IfcSchema::Type::IfcSIUnit)) {
|
2015-11-21 23:05:28 +02:00
|
|
|
siunit = (IfcSchema::IfcSIUnit*) mu->UnitComponent();
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
} else if (named_unit->is(IfcSchema::Type::IfcSIUnit)) {
|
2015-11-21 23:05:28 +02:00
|
|
|
return_value.first = siunit = (IfcSchema::IfcSIUnit*) named_unit;
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
2015-11-21 23:05:28 +02:00
|
|
|
if (siunit) {
|
|
|
|
|
if (siunit->hasPrefix()) {
|
|
|
|
|
return_value.second *= IfcSIPrefixToValue(siunit->Prefix());
|
2015-02-17 19:48:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return return_value;
|
2016-05-15 15:47:21 +02:00
|
|
|
}
|