PyRx icon indicating copy to clipboard operation
PyRx copied to clipboard

Wrap BrxBim classes

Open CEXT-Dan opened this issue 1 year ago • 45 comments

@CEXT-Dan hope you're well. Could use functionality to import 1) IFC, 2) classify entities (for example by layer name) and 3) export to IFC. I believe it's all BCAD verticals. I am aware that there may be other priorities. Whenever you find the time I would be grateful to be able to script anything.

  1. https://help.bricsys.com/en-us/document/command-reference/i/import-command?version=V24&id=165079082118
  2. https://help.bricsys.com/en-us/document/bricscad-bim/building-data/bim-classify?version=V24&id=165079158884
  3. https://help.bricsys.com/en-us/document/command-reference/i/ifcexport-command?version=V24&id=165079081611

Have in mind that you're about to travel for longer. Wish you safe journey.

Originally posted by @schoeller in https://github.com/CEXT-Dan/PyRx/issues/5#issuecomment-2211708315

CEXT-Dan avatar Jul 07 '24 13:07 CEXT-Dan

In progress, est two-three weeks

CEXT-Dan avatar Jul 07 '24 13:07 CEXT-Dan

Saw that you're back online. Hope you're well. Please signal whenever I becomes reasonable to attempt scripting BRX24.2.03.0\samples\brxBimSample\BimIfcImport.cpp

schoeller avatar Aug 27 '24 17:08 schoeller

I’m going to defer this until V25 is released, reason is, there appears API changes between beta versions. I find myself having to redo stuff.

CEXT-Dan avatar Sep 03 '24 00:09 CEXT-Dan

Saw that you're back online. Hope you're well. Please signal whenever I becomes reasonable to attempt scripting BRX24.2.03.0\samples\brxBimSample\BimIfcImport.cpp

Hi, do you have any sample data I can use to test? I'll try to push hard on this next week. Admittedly, this wrap is hard for me, I've never worked with BIM.

CEXT-Dan avatar Sep 05 '24 23:09 CEXT-Dan

Saw that you're back online. Hope you're well. Please signal whenever I becomes reasonable to attempt scripting BRX24.2.03.0\samples\brxBimSample\BimIfcImport.cpp

Hi, do you have any sample data I can use to test? I'll try to push hard on this next week. Admittedly, this wrap is hard for me, I've never worked with BIM.

Hi as well. I just tried sample data from BuildingSMART. Works as manual import into v24. Hope distraction from vanilla work does not cause too many headaches.

From my current understanding the BCAD BIM (in this case) consists of two parts:

1#Import of geometries into ACIS objects from IFC 2x3 up to 4.1. grafik

2#Classification of existing objects through a defined tag-catalogue. grafik

In a current project it would be a time-saver to mass-convert incoming IFC-files to DWG to assemble a collision model (1#). Second goal would be to sync object classification <-> layer structure.

Best wishes.

Seb

schoeller avatar Sep 06 '24 11:09 schoeller

@CEXT-Dan I saw the code snipped from your work. I have tried to load it with the file path correctly set. It messages as follows:

onIfcProduct 94257
<PyBrxBim.IfcImportContext object at 0x00000000030F1F40> False
True

I do not see any objects imported though. I cannot get around figuring out the usage of Bim.IfcImportReactor. Is it already possible to sideload (convert) an IFC to DWG and how would I do that? Best Seb

schoeller avatar Sep 20 '24 06:09 schoeller

Hi, it's not ready yet.

CEXT-Dan avatar Sep 20 '24 13:09 CEXT-Dan

I can import the sample from building smart on a local compile. However, I’m having trouble in that onIfcProductImported is never called. It’s not called in the BRX sample either. onIfcProduct is called, however, matrix = context.getLocalPlacement(entity) always returns an identity, This is also the same with the BRX sample. I’m not sure if this is by design or if BRX has issues. I’ll work this week on filling in the gaps for importing, I expect there will be issues

CEXT-Dan avatar Oct 14 '24 07:10 CEXT-Dan

SR 184312 asks for help

CEXT-Dan avatar Oct 14 '24 08:10 CEXT-Dan

I can import the sample from building smart on a local compile. However, I’m having trouble in that onIfcProductImported is never called. It’s not called in the BRX sample either. onIfcProduct is called, however, matrix = context.getLocalPlacement(entity) always returns an identity, This is also the same with the BRX sample. I’m not sure if this is by design or if BRX has issues. I’ll work this week on filling in the gaps for importing, I expect there will be issues

I have seen the following in the SDK as well as samples\brxBimSample\BimIfcImport.cpp. Everything else is out of my league

grafik

schoeller avatar Oct 14 '24 08:10 schoeller

I had set new guid in https://github.com/CEXT-Dan/PyRx/blob/main/PySamples/PyBrxBim/importTest.py

onStart, onIfcProduct, and beforeCompletion are called correctly. My guess is that onIfcProductImported has lost its “virtual” status due to some internal change. I still have lots of work on other items in BIM while I wait on the SR… I’ll make a release Thursday as a progress build

CEXT-Dan avatar Oct 14 '24 09:10 CEXT-Dan

I had set new guid in https://github.com/CEXT-Dan/PyRx/blob/main/PySamples/PyBrxBim/importTest.py

onStart, onIfcProduct, and beforeCompletion are called correctly. My guess is that onIfcProductImported has lost its “virtual” status due to some internal change. I still have lots of work on other items in BIM while I wait on the SR… I’ll make a release Thursday as a progress build

Sorry to have bothered you with this workload.

schoeller avatar Oct 14 '24 11:10 schoeller

Is it somehow possible to fetch properties from Mechanical info (1#) (for example through dump functionality) and copy it into a custom BIM properties set (2#)? Just curious to save us tons of hours.

1#

2#

schoeller avatar Oct 14 '24 11:10 schoeller

Not sure about that off the top of my head I noticed the mechanical sample that has access to properties. I know Bricsys has a cool properties class for vanilla BricsCAD, I have not wrapped either yet

CEXT-Dan avatar Oct 15 '24 08:10 CEXT-Dan

Not sure about that off the top of my head I noticed the mechanical sample that has access to properties. I know Bricsys has a cool properties class for vanilla BricsCAD, I have not wrapped either yet

@CEXT-Dan: Thx for the feedback. We will try ourselves with LISP standard tools for the mo. Best of health.

schoeller avatar Oct 15 '24 12:10 schoeller

Bricsys was able to reproduce the import reactor issue, I don’t think they will be working on a V24 fix, since V25 is just around the corner. I’ll continue working on Bim wrappers, albeit with a lower priority

CEXT-Dan avatar Oct 15 '24 22:10 CEXT-Dan

Seems Bricsys does not want to support me on this project. Closing until something changes

CEXT-Dan avatar Nov 07 '24 23:11 CEXT-Dan

Advise is requested:

import traceback
from pyrx_imp import Rx, Ge, Gs, Gi, Db, Ap, Ed, Bim

import wx
import os, pathlib

def openIfcSideDrawing(path, opts):
    print("\nProcessing {} ".format(path))
    db = Db.Database(False, True)
    Bim.IfcImportOptions.importIfcFile(db, path, opts)
    path = str(path[:-3]) + "dwg"
    print(path)
    db.saveAs("c://temp/test.dwg")
    db.closeInput(True)
            
def PyRxCmd_doit1():
    try:
        ifcext = ".ifc".casefold()
        opts = Bim.IfcImportOptions()

        dlg = wx.DirDialog(None, "Choose input directory","",
                wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
    
        if dlg.ShowModal() != wx.ID_OK:
            print("You Cancelled The Dialog!")
            return

        for fname in next(os.walk(dlg.GetPath()), (None, None, []))[2]:
            ext = pathlib.Path(fname).suffix.casefold()
            if ext != ifcext:
                continue
            fpath = '{}\\{}'.format(dlg.GetPath(),fname)
            print(fpath)
            openIfcSideDrawing(fpath, opts)
    except Exception as err:
        traceback.print_exception(err)

leads to

Processing C:\Users\Sebastian Schoeller\Downloads\Ifc\13-02_40-00_IWP.ifc 
C:\Users\Sebastian Schoeller\Downloads\Ifc\13-02_40-00_IWP.dwg
Traceback (most recent call last):
  File "C:\Users\Sebastian Schoeller\Nextcloud\10000-Beruf\02-Software\PyRx\ConvertIfc.py", line 34, in PyRxCmd_doit1
    openIfcSideDrawing(fpath, opts)
  File "C:\Users\Sebastian Schoeller\Nextcloud\10000-Beruf\02-Software\PyRx\ConvertIfc.py", line 13, in openIfcSideDrawing
    db.saveAs("c://temp/test.dwg")
PyDb.ErrorStatusException: Exception!(eFileAccessErr), function saveAs1, Line 2150, File PyDbDatabase.cpp:

schoeller avatar Nov 21 '24 11:11 schoeller

this works for me, see my comment also, make sure c:/temp/test.dwg is not opened already

import traceback
from pyrx_imp import Rx, Ge, Gs, Gi, Db, Ap, Ed, Bim

import wx
import os, pathlib

def openIfcSideDrawing(path, opts):
    print("\nProcessing {} ".format(path))
    
    # the ctor is going to change because in this case you are creating 
    # a new drawing which also needs a new document 
    db = Db.Database(True, False) 
    Bim.IfcImportOptions.importIfcFile(db, path, opts)
    path = str(path[:-3]) + "dwg"
    print(path)
    db.saveAs("c:/temp/test.dwg")
    #not needed, this is for reading exisiting drawings
    #db.closeInput(True)
            
def PyRxCmd_doit1():
    try:
        ifcext = ".ifc".casefold()
        opts = Bim.IfcImportOptions()

        dlg = wx.DirDialog(None, "Choose input directory","",
                wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
    
        if dlg.ShowModal() != wx.ID_OK:
            print("You Cancelled The Dialog!")
            return

        for fname in next(os.walk(dlg.GetPath()), (None, None, []))[2]:
            ext = pathlib.Path(fname).suffix.casefold()
            if ext != ifcext:
                continue
            fpath = '{}\\{}'.format(dlg.GetPath(),fname)
            print(fpath)
            openIfcSideDrawing(fpath, opts)
    except Exception as err:
        traceback.print_exception(err)

db

CEXT-Dan avatar Nov 21 '24 12:11 CEXT-Dan

oh! also db.saveAs("c:/temp/test.dwg") is in a loop, so if you have more than one .ICF file if will fail because c:/temp/test.dwg is already there

CEXT-Dan avatar Nov 21 '24 12:11 CEXT-Dan

Thx. Blindfolded. This works for me now:

def openSaveIfcSideDrawing(path, opts):
    print("\nProcessing {} ".format(path))
    db = Db.Database(True, False)
    Bim.IfcImportOptions.importIfcFile(db, path, opts)
    path = str(path[:-3]) + "dwg"
    db.saveAs(path)
    print("\nSaved to {} ".format(path))
    db.closeInput(True)

schoeller avatar Nov 21 '24 13:11 schoeller

I’m not sure what to do with this task. The import reactor, (which seems like the most important feature? ) does not work in V24 or V25. I think the class layout is mostly done. I’ll reopen this so it can be worked on. Maybe there’s some other important features, I don’t really understand BIM

CEXT-Dan avatar Nov 21 '24 20:11 CEXT-Dan

Started test scripting the sample from BRX25.1.05.0\samples\brxBimSample\BimClassification.cpp. Noticed that Bim.BimStory.setDescription was non-existant. Compared BRX25.1.05.0\inc\BrxSpecific\bim\BuildingElements.h to PyBrxBimObject.h and have openend a pull request for what I thought to be useful with focus on BimStory.

When doing

ourBuilding = Bim.BimBuilding.createNewBuilding(db, "TowerNorth")
ourBuilding.setDescription("the north side tower building")
floor_1 = Bim.BimStory.createNewStory(db, "TowerNorth", "Floor 1")

all nice, but

floor_2 = Bim.BimStory.createStory("second floor", ourBuilding)

throws

    floor_2 = Bim.BimStory.createStory("second floor", ourBuilding)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Boost.Python.ArgumentError: Python argument types in
    BimStory.createStory(str, BimBuilding)
did not match C++ signature:
    createStory(class PyBrxBimStory {lvalue}, class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >, class PyBrxBimBuilding)

schoeller avatar Nov 25 '24 10:11 schoeller

When trying as per SDK

    // assign floors & building to "hull entities"
    AcDbObjectId idBuilding;
    AcDbObjectIdArray idsForBuilding;
    bimRes = ourBuilding.assignedObjects(idsForBuilding, pDb);
    if (idsForBuilding.isEmpty())
    {
        idBuilding = createBoxSolid(100, 35, 20, AcGeVector3d(0,0,10.0), 1);
        bimRes = ourBuilding.assignToEntity(idBuilding);
    }

in the fashion


        db = Db.curDb()
        model = Db.BlockTableRecord(Db.curDb().modelSpaceId(), Db.OpenMode.ForRead)

        ourBuilding = Bim.BimBuilding.createNewBuilding(db, "TowerNorth")
        ourBuilding.setDescription("the north side tower building")

        if not ourBuilding.assignedObjects(db):
            print("creating building elements")
            box =  Db.Solid3d()
            box.createBox(100.0,35.0,20.0) # createBoxSolid(100, 35, 20, AcGeVector3d(0,0,10.0), 1); add vector
            model.upgradeOpen()
            model.appendAcDbEntity(box)
            ourBuilding.assignToEntity(box.id())
            model.downgradeOpen()

I see no properties attached to the solid.

schoeller avatar Nov 25 '24 10:11 schoeller

Started test scripting the sample from BRX25.1.05.0\samples\brxBimSample\BimClassification.cpp. Noticed that Bim.BimStory.setDescription was non-existant. Compared BRX25.1.05.0\inc\BrxSpecific\bim\BuildingElements.h to PyBrxBimObject.h and have openend a pull request for what I thought to be useful with focus on BimStory.

When doing

ourBuilding = Bim.BimBuilding.createNewBuilding(db, "TowerNorth")
ourBuilding.setDescription("the north side tower building")
floor_1 = Bim.BimStory.createNewStory(db, "TowerNorth", "Floor 1")

all nice, but

floor_2 = Bim.BimStory.createStory("second floor", ourBuilding)

throws

    floor_2 = Bim.BimStory.createStory("second floor", ourBuilding)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Boost.Python.ArgumentError: Python argument types in
    BimStory.createStory(str, BimBuilding)
did not match C++ signature:
    createStory(class PyBrxBimStory {lvalue}, class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >, class PyBrxBimBuilding)

createStory is not static

def PyRxCmd_doit():
    try:
        db = Db.curDb()
        ourBuilding = Bim.BimBuilding.createNewBuilding(db, "TowerNorth")
        ourBuilding.setDescription("the north side tower building")
        floor_1 = Bim.BimStory.createNewStory(db, "TowerNorth", "Floor 1")

        floor_2 = Bim.BimStory()
        floor_2.createStory("second floor", ourBuilding)

        print(
            ourBuilding.description(),
            floor_2.getBuilding().description() == ourBuilding.description(),
        )

    except Exception as err:
        traceback.print_exception(err)

CEXT-Dan avatar Nov 25 '24 23:11 CEXT-Dan

if not ourBuilding.assignedObjects(db):

looks like a bug in BricsCAD. the function succeeds;

from pyrx_imp import Rx, Ge, Gs, Gi, Db, Ap, Ed, Bim
import traceback

def PyRxCmd_doit():
    try:
        db = Db.curDb()
        ourBuilding = Bim.BimBuilding.createNewBuilding(db, "TowerNorth")
        ourBuilding.setDescription("the north side tower building")
        ourBuilding.setName("TowerNorth")
        ourBuilding.setLongName("TowerNorth")

        if not ourBuilding.assignedObjects(db):
            print("creating building elements")
            box =  Db.Solid3d()
            box.createBox(100.0,35.0,20.0)
            box.transformBy(Ge.Matrix3d.translation(Ge.Vector3d(0,0,10.0)))
            bid = db.addToModelspace(box)
            ourBuilding.assignToEntity(bid)
    except Exception as err:
        traceback.print_exception(err)

setdesc

BTW, db.addToModelspace is a shortcut for having to deal with model

CEXT-Dan avatar Nov 25 '24 23:11 CEXT-Dan

Comparing BuildingElements.h to PyBrxBimObject.h for PyBrxBimClassification. Have seen that there are some double entries like below

static BimApi::ResultStatus classifyAs(const AcDbObjectId& id, const BimApi::BimElementType objectType);
static BimApi::ResultStatus classifyAs(const AcDbObjectId& id, const AcString& typeName, bool localName = false);    

schoeller avatar Nov 26 '24 17:11 schoeller

Comparing BuildingElements.h to PyBrxBimObject.h for PyBrxBimClassification. Have seen that there are some double entries like below

static BimApi::ResultStatus classifyAs(const AcDbObjectId& id, const BimApi::BimElementType objectType);
static BimApi::ResultStatus classifyAs(const AcDbObjectId& id, const AcString& typeName, bool localName = false);    

Unless we know for certain that one method is depreciated, we have to do both, we don’t know if the user will run into a situation where the overload is required

edit: Just to add, of course, you can only do the functions you need to get your project working, maybe leave a TODO comment that the class is incomplete

CEXT-Dan avatar Nov 26 '24 21:11 CEXT-Dan

Have no idea what I am doing. How would this translate in BuildingElements.h?

class BRX_IMPORTEXPORT BimClassification
...
static BimApi::ResultStatus getClassification(AcString& typeName, const AcDbObjectId& id, bool localName = false);
...

schoeller avatar Nov 27 '24 21:11 schoeller

Have no idea what I am doing. How would this translate in BuildingElements.h?

class BRX_IMPORTEXPORT BimClassification
...
static BimApi::ResultStatus getClassification(AcString& typeName, const AcDbObjectId& id, bool localName = false);
...

it's a hard class, I committed and update,I will finish it when I am back later today

CEXT-Dan avatar Nov 28 '24 00:11 CEXT-Dan