hlorus / CAD_Sketcher

Constraint-based geometry sketcher for blender
GNU General Public License v3.0
2.71k stars 130 forks source link

Add integration with IFC #26

Open Moult opened 2 years ago

Moult commented 2 years ago

Motivation / Existing Problem IFC is a way of describing parametric geometry in the world of BIM (Building Information Management - basically the schema for digital buildings). Right now there is no nice UX for modifying these parametric profiles in Blender.

Description I'd love to collaborate with the geometry sketcher plugin to integrate with IFC. Would you be interested in a collaboration or redesigning the plugin so it is more agnostic / generic and can be called from other add-ons too?

Moult commented 2 years ago

Link to https://github.com/IfcOpenShell/IfcOpenShell/issues/1641

hlorus commented 2 years ago

Hey there, Such an integration would be awesome! I'd like to help making that happen.

How would such a redesign be, is there something specific you already imagine?

I think you've said that it should be possible to import the addon or parts of it from another addon, right? How would registration of operators and properties happen in such a scenario?

Moult commented 2 years ago

I'm not quite sure, I haven't yet had the chance to code dive :) IFC supports defining certain types of geometry. One of these is a polycurve consisting of straight lines and arc segments: http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcIndexedPolyCurve.htm

If I am able to process the IFC polycurve into something that geometry_sketcher can understand, is there some function that can be called to render the profile on the screen so the user can edit it? Once edited, can I insert a callback, listener, hook or perhgaps write my own operator that stops rendering the profile on the screen and receives the edited profile from geometry_sketcher so that I can convert it back into an IFC polycurve?

Moult commented 2 years ago

Would you be available for a short call to discuss and I can demo how things work in IFC and discuss how an integration might work?

theoryshaw commented 2 years ago

I would love to see this as well!

Could see CAD_Sketcher being the in-world editor for all IfcProfileDef's

If you need some simple examples from FreeMVD


IFCRECTANGLEPROFILEDEF schema definition here

  /*#237=IFCEXTRUDEDAREASOLID(#231,#235,#236,6.56167979002625);*/
    /*#231=IFCRECTANGLEPROFILEDEF(.AREA.,$,$,5.90551160243344,2.62467200889831);*/
    /*#235=IFCAXIS2PLACEMENT3D(#232,#233,#234);*/
      /*#232=IFCCARTESIANPOINT((2.28083978487751,-2.64041986208888,1.00000011013562));*/
      /*#233=IFCDIRECTION((0.,-0.,-1.));*/
      /*#234=IFCDIRECTION((-1.,0.,0.));*/
    /*#236=IFCDIRECTION((0.,0.,-1.));*/

IFCCIRCLEPROFILEDEF schema definition here

  /*#208=IFCEXTRUDEDAREASOLID(#202,#206,#207,2.99999996554407);*/
    /*#202=IFCCIRCLEPROFILEDEF(.AREA.,$,#201,0.499189355954731);*/
      /*#201=IFCAXIS2PLACEMENT2D(#199,#200);*/
        /*#199=IFCCARTESIANPOINT((0.,0.));*/
        /*#200=IFCDIRECTION((1.,0.));*/
    /*#206=IFCAXIS2PLACEMENT3D(#203,#204,#205);*/
      /*#203=IFCCARTESIANPOINT((1.60414813541052E-08,-2.2916401934436E-09,-1.00000069679551));*/
      /*#204=IFCDIRECTION((3.7878029957028E-07,2.31496199987191E-09,-1.));*/
      /*#205=IFCDIRECTION((-0.0578654408454895,-0.998324334621429,0.));*/
    /*#207=IFCDIRECTION((-3.91146457445757E-08,1.79253149212855E-07,-0.999999940395355));*/

IFCARBITRARYPROFILEDEFWITHVOIDS schema definition here

  /*#194=IFCEXTRUDEDAREASOLID(#188,#192,#193,3.);*/
    /*#188=IFCARBITRARYPROFILEDEFWITHVOIDS(.AREA.,$,#182,(#187));*/
      /*#182=IFCPOLYLINE((#178,#179,#180,#181,#178));*/
        /*#178=IFCCARTESIANPOINT((-0.500000006179484,-0.49999995729116));*/
        /*#179=IFCCARTESIANPOINT((0.500000006179484,-0.49999995729116));*/
        /*#180=IFCCARTESIANPOINT((0.500000006179484,0.500000348397753));*/
        /*#181=IFCCARTESIANPOINT((-0.500000006179484,0.500000348397753));*/
        /*#178=IFCCARTESIANPOINT((-0.500000006179484,-0.49999995729116));*/
      /*#187=IFCPOLYLINE((#183,#184,#185,#186,#183));*/
        /*#183=IFCCARTESIANPOINT((-0.353553393498806,1.95553296507187E-07));*/
        /*#184=IFCCARTESIANPOINT((0.,-0.353553124613023));*/
        /*#185=IFCCARTESIANPOINT((0.353553393498806,1.95553296507187E-07));*/
        /*#186=IFCCARTESIANPOINT((0.,0.353553613496265));*/
        /*#183=IFCCARTESIANPOINT((-0.353553393498806,1.95553296507187E-07));*/
    /*#192=IFCAXIS2PLACEMENT3D(#189,#190,#191);*/
      /*#189=IFCCARTESIANPOINT((1.77188495325604,0.,2.34991546690933));*/
      /*#190=IFCDIRECTION((0.70710676908493,0.,0.70710676908493));*/
      /*#191=IFCDIRECTION((0.,1.,0.));*/
    /*#193=IFCDIRECTION((0.,0.,1.));*/

IFCARBITRARYCLOSEDPROFILEDEF schema definition here

          /*#365= IFCEXTRUDEDAREASOLID(#359,#364,#20,3.);*/
            /*#359= IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,'Generic Models 1',#352);*/
              /*#352= IFCCOMPOSITECURVE((#324,#331,#338,#344,#351),.F.);*/
                /*#324= IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#322);*/
                  /*#322= IFCPOLYLINE((#318,#320));*/
                    /*#318= IFCCARTESIANPOINT((-0.500000000000002,-0.5));*/
                    /*#320= IFCCARTESIANPOINT((0.499999999999998,-0.5));*/
                /*#331= IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#329);*/
                  /*#329= IFCPOLYLINE((#325,#327));*/
                    /*#325= IFCCARTESIANPOINT((0.499999999999998,-0.5));*/
                    /*#327= IFCCARTESIANPOINT((0.5,0.499999999999998));*/
                /*#338= IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#336);*/
                  /*#336= IFCPOLYLINE((#332,#334));*/
                    /*#332= IFCCARTESIANPOINT((0.5,0.499999999999998));*/
                    /*#334= IFCCARTESIANPOINT((-0.,0.500000000000001));*/
                /*#344= IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#341);*/
                  /*#341= IFCTRIMMEDCURVE(#340,(IFCPARAMETERVALUE(360.)),(IFCPARAMETERVALUE(90.)),.T.,.PARAMETER.);*/
                    /*#340= IFCCIRCLE(#339,0.5);*/
                      /*#339= IFCAXIS2PLACEMENT2D(#10,#28);*/
                        /*#10= IFCCARTESIANPOINT((0.,0.));*/
                        /*#28= IFCDIRECTION((0.,1.));*/
                /*#351= IFCCOMPOSITECURVESEGMENT(.CONTINUOUS.,.T.,#349);*/
                  /*#349= IFCPOLYLINE((#345,#347));*/
                    /*#345= IFCCARTESIANPOINT((-0.500000000000001,0.));*/
                    /*#347= IFCCARTESIANPOINT((-0.500000000000002,-0.5));*/
            /*#364= IFCAXIS2PLACEMENT3D(#360,#362,#18);*/
              /*#360= IFCCARTESIANPOINT((0.353553390593275,0.500000000000007,0.358787223388274));*/
              /*#362= IFCDIRECTION((0.707106781186547,0.,0.707106781186548));*/
              /*#18= IFCDIRECTION((0.,-1.,0.));*/
            /*#20= IFCDIRECTION((0.,0.,1.));*/

IFCISHAPEPROFILEDEF schema definition here

#541=IFCEXTRUDEDAREASOLID(#75,$,#540,2.);
  /*#75=IFCISHAPEPROFILEDEF(.AREA.,'This is the profile name',$,0.100000001490116,0.319999992847443,0.00499999988824129,0.00999999977648258,0.00499999988824129,$,$);*/
Moult commented 2 years ago

Apart from the primitives and parametric profiles, I reckon the biggest advantage would be the ability to author IfcIndexedPolyCurve which is effectively a polyline which supports arc segments.

hlorus commented 2 years ago

Would you be available for a short call to discuss and I can demo how things work in IFC and discuss how an integration might work?

Yeah sure, how about tomorrow (Wednesday) afternoon?

theoryshaw commented 2 years ago

You can have multiple profiles in one 'mesh', as well.

IFCSHAPEREPRESENTATION schema definition here

        /*#246= IFCSHAPEREPRESENTATION(#127,'Body','SweptSolid',(#211,#219,#245));*/
          /*#127= IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#121,$,.MODEL_VIEW.,$);*/
            /*#121= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,0.0001,#118,#119);*/
              /*#118= IFCAXIS2PLACEMENT3D(#6,$,$);*/
                /*#6= IFCCARTESIANPOINT((0.,0.,0.));*/
              /*#119= IFCDIRECTION((6.12303176911189E-17,1.));*/
          /*#211= IFCEXTRUDEDAREASOLID(#205,#210,#20,5.);*/
            /*#205= IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,'Generic Models 1',#203);*/
              /*#203= IFCPOLYLINE((#197,#199,#201,#197));*/
                /*#197= IFCCARTESIANPOINT((-0.5,-0.333333333333333));*/
                /*#199= IFCCARTESIANPOINT((0.5,-0.333333333333333));*/
                /*#201= IFCCARTESIANPOINT((0.,0.666666666666667));*/
                /*#197= IFCCARTESIANPOINT((-0.5,-0.333333333333333));*/
            /*#210= IFCAXIS2PLACEMENT3D(#208,#16,#14);*/
              /*#208= IFCCARTESIANPOINT((2.49999999999999,-5.,0.333333333333327));*/
              /*#16= IFCDIRECTION((0.,1.,0.));*/
              /*#14= IFCDIRECTION((-1.,0.,0.));*/
            /*#20= IFCDIRECTION((0.,0.,1.));*/
          /*#219= IFCEXTRUDEDAREASOLID(#215,#218,#20,5.);*/
            /*#215= IFCCIRCLEPROFILEDEF(.AREA.,'Generic Models 1',#214,0.5);*/
              /*#214= IFCAXIS2PLACEMENT2D(#212,#24);*/
                /*#212= IFCCARTESIANPOINT((-2.84968587332237E-30,-2.27595720048157E-15));*/
                /*#24= IFCDIRECTION((1.,0.));*/
            /*#218= IFCAXIS2PLACEMENT3D(#216,#16,#12);*/
              /*#216= IFCCARTESIANPOINT((4.49999999999999,-5.,0.499999999999985));*/
              /*#16= IFCDIRECTION((0.,1.,0.));*/
              /*#12= IFCDIRECTION((1.,0.,0.));*/
            /*#20= IFCDIRECTION((0.,0.,1.));*/
          /*#245= IFCEXTRUDEDAREASOLID(#240,#244,#20,5.);*/
            /*#240= IFCARBITRARYPROFILEDEFWITHVOIDS(.AREA.,'Generic Models 1',#228,(#238));*/
              /*#228= IFCPOLYLINE((#220,#222,#224,#226,#220));*/
                /*#220= IFCCARTESIANPOINT((-0.5,-0.5));*/
                /*#222= IFCCARTESIANPOINT((0.5,-0.5));*/
                /*#224= IFCCARTESIANPOINT((0.5,0.5));*/
                /*#226= IFCCARTESIANPOINT((-0.5,0.5));*/
                /*#220= IFCCARTESIANPOINT((-0.5,-0.5));*/
              /*#238= IFCPOLYLINE((#230,#232,#234,#236,#230));*/
                /*#230= IFCCARTESIANPOINT((-0.25,0.25));*/
                /*#232= IFCCARTESIANPOINT((0.25,0.25));*/
                /*#234= IFCCARTESIANPOINT((0.25,-0.25));*/
                /*#236= IFCCARTESIANPOINT((-0.25,-0.25));*/
                /*#230= IFCCARTESIANPOINT((-0.25,0.25));*/
            /*#244= IFCAXIS2PLACEMENT3D(#242,#16,#14);*/
              /*#242= IFCCARTESIANPOINT((0.499999999999988,-5.,0.5));*/
              /*#16= IFCDIRECTION((0.,1.,0.));*/
              /*#14= IFCDIRECTION((-1.,0.,0.));*/
            /*#20= IFCDIRECTION((0.,0.,1.));*/
Moult commented 2 years ago

So sorry I missed your message @hlorus - I'm online in general in the OSArch chatroom during the Sydney timezone. @qwiglydee is also helping hack on the BlenderBIM Add-on and can also find him online in the chatroom feel free to ping us anytime :)

Essentially to integrate with IFC:

  1. What function should we call from the BlenderBIM Add-on to programatically display a profile using cad-sketcher?
  2. What is the format cad-sketcher needs us to describe the input profile to generate any profile that we need? We can build an IFC Profile->CAD Sketcher Profile converter.
  3. After the user modifies that profile what function should we call to stop displaying that editable profile on the screen using CAD sketcher?
  4. What is the output format we can extract of the saved profile? We can build a CAD Sketcher Profile -> IFC Profile converter here.

The first profile I'd like to see being able to convert to and from IFC / CAD Sketcher is an IfcIndexedPolyCurve: http://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcIndexedPolyCurve.htm

image

It's pretty straightforward, essentially a polyline, where a segment may either be a straight line, or a circular arc. So as long as you can translate to and from a list of sequential points, that's all we need. To represent the arc, it is represented by 3 points - the start, end, and point on the arc (let's go for midpoint).

Does this sound achievable? If you can help point us to some functions to call and examples of inputs and outputs, I can help link it up to IFC and @qwiglydee and write the GUI integration and any necessary math to convert arcs and points and so on.

hlorus commented 2 years ago

So sorry I missed your message @hlorus

No problem at all!

  1. What function should we call from the BlenderBIM Add-on to programatically display a profile using cad-sketcher?

Due to the parametric nature of the addon geometry is always represent as bpy properties which get stored to disk. In order to manipulate/access and display this data the addon(or just the properties) have to be registered in blender.

If the addon is registered and enabled there's nothing else required, to display a profile, besides creating the CAD Sketcher data.

  1. What is the format cad-sketcher needs us to describe the input profile to generate any profile that we need? We can build an IFC Profile->CAD Sketcher Profile converter.

The addons data is defined in class_defines.py, there's some inital documentation here. Data is currently stored on the scene type so everything can be accessed through bpy.context.scene.sketcher. So to describe a profile you would need to add the individual entities with the add functions (e.g. context.scene.sketcher.entities.add_point_3d(position)). Most of the entity types will require other entities and will depend on them(to create a 3d line you have to define two 3d points first).

You'll want to create a sketch to define the profile. A sketch is currently always based on a workplane however you can use one of the origin workplanes: entities = context.scene.sketcher.entities entities.ensure_origin_elements(context) wp = entities.origin_plane_XY sketch = entities.add_sketch(wp)

  1. After the user modifies that profile what function should we call to stop displaying that editable profile on the screen using CAD sketcher?

Entities have a "visible" property which can be used to hide them. Entities that are part of a sketch will also not be drawn if the sketch is set to not be visible.

Alternatively you could just delete the entities: entities.remove(some_entity.slvs_index) The remove operator also supports deleting a whole sketch recursively: bpy.ops.view3d.slvs_delete_entity(index=sketch.slvs_index)

  1. What is the output format we can extract of the saved profile? We can build a CAD Sketcher Profile -> IFC Profile converter here.

Conversion simply happens by going through the entities and accessing their properties. I've written a walker (in convertors.py) which can return a list of paths(connected segment entities). This can probably be reused.

For better integration i've looked into adding a event system, there's now a branch for that. Also there's the integration branch which intends to add a basic integration API, what do you think about having CAD Sketcher as a dependency and enabling it from within another addon?

Moult commented 2 years ago

This is awesome and your tips made it easy to integrate! Apologies for the delay, I originally wanted to sponsor work by @qwiglydee to work on this but alas it didn't happen.

I've now done a couple prototype operators to allow editing of arbitrary polyline profiles (i.e. no arcs, circles, etc) with CAD sketcher: https://github.com/IfcOpenShell/IfcOpenShell/commit/4c7a5e8a1a9887bd7696f0872920fdebe4eb66cd just to see what the workflow might be like.

It's a promising start but I have some nagging thoughts that suggest it may not be appropriate for some tasks in the BIM world. The BIM world relies a lot more on non-parametric "arbitrary" locations. Just "move this dot here" for example. It also relies a lot of "move this here to align with this edge/corner/whatever of this other 3D object", which CAD sketcher at its current functionality doesn't do very well compared to the OOTB Blender functions of pushing vertices and edges around. I think this means that CAD sketcher should be provided as one option (which might suite well for assembly style part modeling), but there should also be another method more catered towards the BIM world (for the majority of usecases of simple profile editing for slabs, gutters, skirting, mullion extrusion profiles, etc).

hlorus commented 2 years ago

Great to see your efforts, if i get it right you've implemented two operators which allows to temporarily display and edit geometry with the CS tools. The major downside here is that you loose the parametric nature of the addon as all the constraints are removed between the edits.

Referencing of meshes and other entities is indeed a big topic which is already on the roadmap however this might take some time to arrive.

Moult commented 2 years ago

Indeed right now all the parametric nature is lost. This is fine for the prototype, and if further development would occur, all parametric entities would have to be serialised and stored in IFC, and then deserialised on load again, and there would be a job in itself to figure out which ones can play nice with IFC and which can only work in Blender. I think this means this topic needs to be revisited in the future :)

hlorus commented 2 years ago

There's now basic support to write out the addon data of a given scene into a file and load it back in, see: https://github.com/hlorus/CAD_Sketcher/commit/7c548e624a725d6bc3760d4648d92d9e1d882371

Here's a testfile to try it: save_load.zip

Moult commented 2 years ago

Awesome :) I've now updated the integration to use the to_dict() and update() methods :) Let's give it a little while to see where users think integration should be pushed, but at least the basics are there.

theoryshaw commented 2 years ago

Excited about this integration. I think the following functionality would make a CadSketcher/BlenderBIM integration more attractive and useful.

theoryshaw commented 2 years ago

@Moult how do you envision eventually codifying these constraints into the IFC file?

Are you thinking it would be similar to what @geometrygym proposed here?

theoryshaw commented 2 years ago

To help with funding, i proposed this project as a possible project for OSArch to center a funding campaign around. https://community.osarch.org/discussion/comment/12859/#Comment_12859