mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 05:10:53 +00:00
Add more idiomatic wrapper wrapper
This commit is contained in:
@@ -8,70 +8,56 @@ http://IfcOpenShell.org
|
|||||||
About this repository
|
About this repository
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
This is an initiative to expose the functionality of IfcOpenShell for parsing and writing IFC files to a Python interface. The creation of a topological representation for building elements using Open Cascade is also wrapped by returning a string serialization of the Open Cascade TopoDS_Shape. Using SWIG a wrapper is obtained for a C++ Class which evaluates its Express attribute names and indices at runtime. The functions created by the SWIG wrapper closely resemble the C++ structure. The idea is to create an additional wrapper around these function in Python that is more idiomatic to Python.
|
This is an initiative to expose the functionality of IfcOpenShell for parsing and writing IFC files to a Python interface. The creation of a topological representation for building elements using Open Cascade is also wrapped by returning a string serialization of the Open Cascade TopoDS_Shape. Using SWIG, a wrapper is obtained for a C++ Class which evaluates its Express attribute names at runtime. The functions created by the SWIG wrapper closely resemble the C++ structure. An additional Python wrapper around these functions is created that is more idiomatic to Python.
|
||||||
|
|
||||||
The following interactive session illustrates its use:
|
The following interactive session illustrates its use:
|
||||||
|
|
||||||
>>> import IfcImport
|
>>> import ifc
|
||||||
>>> f = IfcImport.open(filename)
|
>>> f = ifc.open("Duplex_A_20110907_optimized.ifc")
|
||||||
>>> f.by_type("ifcwall")
|
>>> f.by_type("ifcwall")[:2]
|
||||||
[#170=IfcWallStandardCase('0lJANQLbCEHPkU1Xq9w_bk',#13,'Wand-001',$,$,#167,#240,'2F4CA5DA-5653-0E45-9B-9E-061D09EBE96E'),
|
[#91=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FL9r',#1,'Basic Wall:Interior - Partition (92mm Stud):144586',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5198,#18806,'144586'), #92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')]
|
||||||
#288=IfcWallStandardCase('1sFBHOg98nGQTuD1XjjAKK',#13,'Wand-002',$,$,#285,#358,'763CB458-A892-3141-A7-78-34186DB4A514')]
|
|
||||||
>>> wall = _[0]
|
>>> wall = _[0]
|
||||||
>>> brep_data = IfcImport.create_shape(wall)
|
>>> brep_data = ifc.create_shape(wall, ifc.SEW_SHELLS)
|
||||||
>>> wall.get_argument_count()
|
>>> len(wall) # number of EXPRESS attributes
|
||||||
8
|
8
|
||||||
>>> wall.get_argument('GlobalId')
|
>>> wall.GlobalId
|
||||||
'0lJANQLbCEHPkU1Xq9w_bk'
|
'2O2Fr$t4X7Zf8NOew3FL9r'
|
||||||
>>> wall.get_argument_index('Name')
|
>>> wall.Name = "My wall"
|
||||||
2
|
>>> wall.NonExistingAttr
|
||||||
>>> wall.set_argument(2,"John")
|
|
||||||
>>> wall.get_argument('Name')
|
|
||||||
'John'
|
|
||||||
>>> wall.get_argument_index("foo")
|
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
File "IfcImport.py", line 112, in get_argument_index
|
File ".\ifc.py", line 14, in __getattr__
|
||||||
def get_argument_index(self, *args): return _IfcImport.Entity_get_argument_index(self, *args)
|
except: raise AttributeError("entity instance of type '%s' has no attribute'%s'"%(self.wrapped_data.is_a(), name)) from None
|
||||||
RuntimeError: Argument foo not found on IfcRoot
|
AttributeError: entity instance of type 'IfcWallStandardCase' has no attribute 'NonExistingAttr'
|
||||||
>>> wall.set_argument(5,"Hi")
|
>>> wall.GlobalId = 3
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
File "IfcImport.py", line 114, in set_argument
|
File ".\ifc.py", line 26, in __setattr__
|
||||||
def set_argument(self, *args): return _IfcImport.Entity_set_argument(self, *args)
|
self[self.wrapped_data.get_argument_index(key)] = value
|
||||||
RuntimeError: STRING is not a valid type for 'ObjectPlacement'
|
File ".\ifc.py", line 30, in __setitem__
|
||||||
>>> e = IfcImport.Entity("IfcJohn")
|
self.wrapped_data.set_argument(idx, entity_instance.map_value(value))
|
||||||
Traceback (most recent call last):
|
File ".\ifc_wrapper.py", line 118, in <lambda>
|
||||||
File "<stdin>", line 1, in <module>
|
set_argument = lambda self,x,y: self._set_argument(x) if y is None else self
|
||||||
File "IfcImport.py", line 105, in __init__
|
._set_argument(x,y)
|
||||||
this = _IfcImport.new_Entity(*args)
|
File ".\ifc_wrapper.py", line 114, in _set_argument
|
||||||
RuntimeError: Unable to find find keyword in schema
|
def _set_argument(self, *args): return _ifc_wrapper.entity_instance__set_argument(self, *args)
|
||||||
>>> pnt = IfcImport.Entity("ifccartesianpoint")
|
RuntimeError: INT is not a valid type for 'GlobalId'
|
||||||
[60478 refs]
|
>>> f.createIfcCartesianPoint(Coordinates=(1.0,1.5,2.0))
|
||||||
>>> pnt.set_argument(0,IfcImport.Doubles([0,0,0]))
|
#27530=IfcCartesianPoint((1.,1.5,2.))
|
||||||
[60486 refs]
|
>>> import uuid
|
||||||
>>> pnt
|
>>> ifc.guid.compress(uuid.uuid1().hex)
|
||||||
=IfcCartesianPoint((0,0,0))
|
'3x4C8Q_6qHuv$P$FYkANRX'
|
||||||
>>> f.add(pnt)
|
>>> new_guid = _
|
||||||
|
>>> owner_hist = f.by_type("IfcOwnerHistory")[0]
|
||||||
|
>>> new_wall = f.createIfcWallStandardCase(new_guid, owner_hist, None, None, Tag='my_tag')
|
||||||
|
>>> new_wall.ObjectType = ''
|
||||||
|
>>> new_wall.ObjectPlacement = new_wall.Representation = None
|
||||||
|
>>> f[92]
|
||||||
|
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
|
||||||
|
>>> f['2O2Fr$t4X7Zf8NOew3FLIE']
|
||||||
|
#92=IfcWallStandardCase('2O2Fr$t4X7Zf8NOew3FLIE',#1,'Basic Wall:Interior - Partition (92mm Stud):143921',$,'Basic Wall:Interior - Partition (92mm Stud):128360',#5206,#18805,'143921')
|
||||||
>>> f.write("out.ifc")
|
>>> f.write("out.ifc")
|
||||||
|
|
||||||
**TODO**: By creating an additional wrapper in Python around these methods some syntactic sugar can be added so one is able to say the following instead:
|
|
||||||
|
|
||||||
d = IfcDocument()
|
|
||||||
my_wall = d.createIfcWallStandardCase("1$gyu8123...",Representation=my_repr)
|
|
||||||
|
|
||||||
With a document specifying a 'catch-all' function that creates the ifc entity based on the method being called, perhaps like so:
|
|
||||||
|
|
||||||
class IfcDocument:
|
|
||||||
def create_entity(self,type,*args,**kwargs):
|
|
||||||
e = new IfcEntity(type)
|
|
||||||
# set all attributes in args and kwargs
|
|
||||||
self.add(e)
|
|
||||||
return e
|
|
||||||
def __getattr__(self,attr):
|
|
||||||
if attr[0:5] == 'create': return functools.partial(self.create_entity,attr[5:])
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
Compiling on Windows
|
Compiling on Windows
|
||||||
====================
|
====================
|
||||||
@@ -120,33 +106,3 @@ If all worked out correctly you can now use IfcOpenShell. For example:
|
|||||||
$ unzip Munkerud_hus6_BE.zip
|
$ unzip Munkerud_hus6_BE.zip
|
||||||
$ ./IfcObj Munkerud_hus6_BE.ifc
|
$ ./IfcObj Munkerud_hus6_BE.ifc
|
||||||
$ less Munkerud_hus6_BE.obj
|
$ less Munkerud_hus6_BE.obj
|
||||||
|
|
||||||
|
|
||||||
Ubuntu Notes
|
|
||||||
============
|
|
||||||
|
|
||||||
The following sequence of commands has been tested successfully on Ubuntu 14.04.
|
|
||||||
|
|
||||||
OCE installation. This step worked OK with cmake 2.8.12.2, gcc 4.8.2, g++ 4.8.2. Also, it might take up to an hour to complete.
|
|
||||||
|
|
||||||
apt-get install git cmake gcc g++ libftgl-dev libtbb2 libtbb-dev libboost-all-dev
|
|
||||||
cd /
|
|
||||||
mkdir git && cd git
|
|
||||||
git clone https://github.com/tpaviot/oce.git
|
|
||||||
mkdir oceBuild && cd oceBuild
|
|
||||||
cmake ../oce
|
|
||||||
make -j4
|
|
||||||
sudo make install
|
|
||||||
|
|
||||||
IfcOpenShell installation. This step worked OK with cmake 2.8.12.2, gcc 4.8.2, g++ 4.8.2.
|
|
||||||
|
|
||||||
apt-get install swig
|
|
||||||
cd /git/
|
|
||||||
git clone https://github.com/aothms/IfcOpenShell.git
|
|
||||||
cd IfcOpenShell/cmake
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake ../
|
|
||||||
make -j4
|
|
||||||
|
|
||||||
Once done, IfcConvert is to be found in the build folder.
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,14 @@
|
|||||||
%ignore operator<<;
|
%ignore operator<<;
|
||||||
|
|
||||||
%rename("by_type") EntitiesByType;
|
%rename("by_type") EntitiesByType;
|
||||||
%rename("get_argument_count") getArgumentCount;
|
%rename("__len__") getArgumentCount;
|
||||||
%rename("get_argument_type") getArgumentType;
|
%rename("get_argument_type") getArgumentType;
|
||||||
%rename("get_argument_name") getArgumentName;
|
%rename("get_argument_name") getArgumentName;
|
||||||
%rename("get_argument_index") getArgumentIndex;
|
%rename("get_argument_index") getArgumentIndex;
|
||||||
%rename("_set_argument") setArgument;
|
%rename("_set_argument") setArgument;
|
||||||
%rename("__repr__") toString;
|
%rename("__repr__") toString;
|
||||||
%rename("Entity") IfcUntypedEntity;
|
%rename("entity_instance") IfcUntypedEntity;
|
||||||
|
%rename("file") IfcFile;
|
||||||
|
|
||||||
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) IfcEntities {
|
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) IfcEntities {
|
||||||
$1 = (PySequence_Check($input) && !PyUnicode_Check($input) && !PyString_Check($input)) ? 1 : 0;
|
$1 = (PySequence_Check($input) && !PyUnicode_Check($input) && !PyString_Check($input)) ? 1 : 0;
|
||||||
@@ -150,7 +151,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
%module IfcImport %{
|
%module ifc_wrapper %{
|
||||||
#include "../ifcparse/IfcException.h"
|
#include "../ifcparse/IfcException.h"
|
||||||
#include "Interface.h"
|
#include "Interface.h"
|
||||||
using namespace IfcParse;
|
using namespace IfcParse;
|
||||||
@@ -181,7 +182,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
%template(Ints) vector<int>;
|
%template(ints) vector<int>;
|
||||||
%template(Doubles) vector<double>;
|
%template(doubles) vector<double>;
|
||||||
%template(Strings) vector<string>;
|
%template(strings) vector<string>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace IfcParse {
|
|||||||
std::string _author_email;
|
std::string _author_email;
|
||||||
std::string _author_organisation;
|
std::string _author_organisation;
|
||||||
public:
|
public:
|
||||||
IfcParse::IfcSpfStream* file;
|
IfcParse::IfcSpfStream* stream;
|
||||||
IfcParse::Tokens* tokens;
|
IfcParse::Tokens* tokens;
|
||||||
bool Init(const std::string& fn);
|
bool Init(const std::string& fn);
|
||||||
IfcEntities EntitiesByType(const std::string& t);
|
IfcEntities EntitiesByType(const std::string& t);
|
||||||
|
|||||||
Reference in New Issue
Block a user