-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
utility methods and spatial structure example
- Loading branch information
Showing
5 changed files
with
238 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package scripts | ||
|
||
import openifctools.com.openifcjavatoolbox.guidcompressor.GuidCompressor | ||
import utils.IfcModelHelper | ||
import openifctools.com.openifcjavatoolbox.ifc2x3tc1.* | ||
import openifctools.com.openifcjavatoolbox.step.parser.util.ProgressEvent | ||
|
||
/** | ||
* @author Helga Tauscher http://github.com/hlg | ||
* @author Robert Kühn http://github.com/rokondo | ||
* | ||
* This file is part of Groovy Ifc Tools, which are distributed | ||
* under the terms of the GNU General Public License version 3 | ||
* http://github.com/hlg/GroovyIFC | ||
* adds geometrical representation to IfcSpatialStructureElements | ||
+ repesentation is taken from an IfcSpace matched by its @longName attribute | ||
+ see marker.site, marker.building, marker.storey | ||
* groups IfcSpaces to complex IfcSpaces | ||
+ group spaces and singular spaces are matched based on their @longName attribute | ||
+ marker.subStorey<X> (space group) consists of spaces marker.subStoreySpace<X> | ||
* groups IfcBuildingStoreys to complex IfcBuildingStoreys | ||
+ complex storeys are identified by their @longName attribute matching marker.storeyGroup | ||
+ singular storeys are assigned by matching their elevation attribute | ||
* assumes all spaces are direct children of storeys in the spatial structure of the original model | ||
*/ | ||
|
||
def printProgress = {ProgressEvent event-> | ||
if (event.currentState == 1) println event.message | ||
print ((event.currentState % 50) ? '.' : '.\n') | ||
} | ||
def model = new IfcModelHelper(progressListener: printProgress, fileName: args[0]) | ||
model.printAsciiTree() | ||
|
||
def copyRepresentation(spaceOrigin, spaceDest) { | ||
spaceDest.representation = spaceOrigin.representation | ||
spaceDest.objectPlacement = spaceOrigin.objectPlacement | ||
} | ||
|
||
def marker = [site: 'CIB_Site', building: 'CIB_Gebaude', storeyGroup: 'CIB_Milestone', storey: 'Bruttogeschoss|BGF', | ||
subStorey: 'Bauabschnitt', subStoreySpace: '-BA'] | ||
|
||
def spaces = model.ifcModel.getCollection(IfcSpace.class) | ||
def storeys = model.ifcModel.getCollection(IfcBuildingStorey.class) | ||
def site = model.ifcModel.ifcObjects.find {it instanceof IfcSite} | ||
def building = model.ifcModel.ifcObjects.find {it instanceof IfcBuilding} | ||
|
||
spaces.findAll {it.longName.value =~ /$marker.site/}.each { dummySite -> | ||
copyRepresentation(dummySite, site) | ||
model.removeDummySpace(dummySite) | ||
} | ||
|
||
spaces.findAll {it.longName.value =~ /$marker.building/}.each {dummyBuilding -> | ||
copyRepresentation(dummyBuilding, building) | ||
model.removeDummySpace(dummyBuilding) | ||
} | ||
|
||
spaces.findAll {it.longName.value =~ /$marker.storey/}.each { dummyStorey -> | ||
dummyStorey.Decomposes_Inverse.each { parentStorey -> // STEP modelling WTF? set of size 0 or 1 | ||
copyRepresentation(dummyStorey, parentStorey.RelatingObject) | ||
model.removeDummySpace(dummyStorey) | ||
} | ||
} | ||
|
||
spaces.findAll {it.longName.toString() =~ /$marker.subStorey/}.each {dummySubStorey -> | ||
dummySubStorey.Decomposes_Inverse.each { parentStorey -> | ||
// TODO: could also be modeled as storey with compositionType PARTIAL | ||
dummySubStorey.compositionType = new IfcElementCompositionEnum('COMPLEX') | ||
def storeySection = dummySubStorey.longName.toString()[-1]; | ||
def subSpaces = parentStorey.relatedObjects.findAll { | ||
it.name.value =~ /$marker.subStoreySpace$storeySection/ | ||
} | ||
parentStorey.removeAllRelatedObjects(subSpaces) | ||
model.builder.relAggregates { | ||
globalId = GloballyUniqueId(GuidCompressor.newIfcGloballyUniqueId) | ||
relatingObject = dummySubStorey | ||
relatedObjects = subSpaces as Set | ||
} | ||
} | ||
} | ||
def sortedGroupStoreys = spaces.findAll {it.longName.toString() =~ /$marker.storeyGroup/}.collect {dummyStoreyGroup -> | ||
dummyStoreyGroup.Decomposes_Inverse.collect { parentStorey -> | ||
def storeyGroup = model.builder.buildingStorey { | ||
globalId = GloballyUniqueId(GuidCompressor.newIfcGloballyUniqueId) | ||
name = new IfcLabel(marker.storeyGroup, false) | ||
longName = new IfcLabel(marker.storeyGroup, false) | ||
compositionType = new IfcElementCompositionEnum('COMPLEX') | ||
elevation = parentStorey.relatingObject.elevation | ||
} | ||
copyRepresentation(dummyStoreyGroup, storeyGroup) | ||
model.removeDummySpace(dummyStoreyGroup) | ||
storeyGroup | ||
} | ||
}.flatten().sort {it.elevation.value}.reverse() | ||
|
||
storeys.groupBy { storey -> | ||
sortedGroupStoreys.find {storey.elevation.value >= it.elevation.value} | ||
}.each { groupDummy, storeysInGroup -> | ||
building.IsDecomposedBy_Inverse.each { parentStorey -> | ||
parentStorey.addRelatedObjects(groupDummy) | ||
parentStorey.removeAllRelatedObjects(storeysInGroup) | ||
} | ||
model.builder.relAggregates { | ||
globalId = GloballyUniqueId(GuidCompressor.newIfcGloballyUniqueId) | ||
relatingObject = groupDummy | ||
relatedObjects = storeysInGroup as Set | ||
} | ||
} | ||
|
||
// save and verify the changed model by parsing it again | ||
model.ifcModel.writeStepfile(new File(args[1])) | ||
model.fileName = args[1] | ||
model.printAsciiTree() | ||
println model.ifcModel.numberOfElements |
18 changes: 13 additions & 5 deletions
18
src/groovy/dae2ifc.groovy → src/groovy/scripts/dae2ifc.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/groovy/IfcBuilder.groovy → src/groovy/utils/IfcBuilder.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package groovy | ||
package utils | ||
|
||
/* Copyright (c) 2010-2011 Helga Tauscher | ||
* http://github.com/hlg/GroovyIFC | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package utils | ||
|
||
import openifctools.com.openifcjavatoolbox.guidcompressor.GuidCompressor | ||
import openifctools.com.openifcjavatoolbox.ifc2x3tc1.IfcBuildingStorey | ||
import openifctools.com.openifcjavatoolbox.ifc2x3tc1.IfcProject | ||
import openifctools.com.openifcjavatoolbox.ifcmodel.IfcModel | ||
import openifctools.com.openifcjavatoolbox.step.parser.util.StepParserProgressListener | ||
import openifctools.com.openifcjavatoolbox.step.parser.util.ProgressEvent | ||
|
||
class IfcModelHelper { | ||
def ifcModel = new IfcModel() | ||
def builder = new IfcBuilder(model: ifcModel) | ||
|
||
void setProgressListener(closure = {ProgressEvent event-> print ((event.currentState % 20) ? '.' : '.\n')}){ | ||
ifcModel.addStepParserProgressListener([progressActionPerformed: closure] as StepParserProgressListener) | ||
} | ||
|
||
void setFileName(String fileName) { | ||
ifcModel.clearModel() | ||
ifcModel.readStepFile(new File(fileName)) | ||
} | ||
|
||
def recursePlacement(localPlacement) { | ||
def result = localPlacement.relativePlacement.location.coordinates[2].value | ||
if (localPlacement.placementRelTo) { | ||
result += recursePlacement(localPlacement.placementRelTo) | ||
} | ||
result | ||
} | ||
|
||
def fixStoreyAssignment(tolerance) { | ||
def storeys = ifcModel.getCollection(IfcBuildingStorey.class) | ||
def rangeMap = storeys.collectEntries { [it, [it.elevation.value + tolerance[0], it.elevation.value + tolerance[1]]] } | ||
storeys.each { storey -> | ||
println "\n*** $storey $storey.elevation" | ||
storey.containsElements_Inverse.each { rel -> | ||
def matched = [:] | ||
rel.relatedElements.each { element -> | ||
// TODO: assertion (z-axis parallel coordinate systems) | ||
def z = recursePlacement(element.objectPlacement) | ||
def matchingStorey = rangeMap.find { k, v -> v[0] <= z && v[1] >= z }.key | ||
if (matchingStorey && (storey != matchingStorey)) { | ||
println "assigning element with z = $z to $matchingStorey" | ||
matched[element] = matchingStorey | ||
} | ||
} | ||
matched.each { element, newStorey -> | ||
rel.removeRelatedElements(element) | ||
if (!newStorey.containsElements_Inverse) { | ||
builder.relContainedInSpatialStructure { | ||
globalId = GloballyUniqueId(GuidCompressor.newIfcGloballyUniqueId) | ||
relatingStructure = newStorey | ||
relatedElements = [element] as Set | ||
} | ||
} else { | ||
newStorey.containsElements_Inverse.each { newRel -> | ||
newRel.addRelatedElements(element) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
def printAsciiTree() { | ||
def spatialRoot = ifcModel.ifcObjects.find {it instanceof IfcProject} | ||
printAsciiTreeRec(spatialRoot, '') | ||
} | ||
|
||
def printAsciiTreeRec(spatial, prefix) { | ||
println "$prefix-$spatial $spatial.name - ${spatial.class.name}"; | ||
def children = spatial.isDecomposedBy_Inverse?.relatedObjects?.flatten() // TODO: Ifc 2x4 nests_Inverse | ||
if (children) { | ||
if (children.size() > 1) { | ||
children[0..-2].each { space -> | ||
printAsciiTreeRec(space, prefix + ' |') | ||
} | ||
} | ||
printAsciiTreeRec(children[-1], prefix + ' ') | ||
} | ||
} | ||
|
||
def removeDummySpace(space) { | ||
// workaround: there is no easy generic way to find referencing relation objects with IFC toolbox | ||
def related = [HasAssignments: 'RelatedObjects', Decomposes: 'RelatedObjects', IsDefinedBy: 'RelatedObjects', | ||
HasAssociations: 'RelatedObjects', ServicedBySystems: 'RelatedBuildings'] | ||
def relating = [IsDecomposedBy: 'RelatingObject', ReferencedBy: 'RelatingProduct', ContainsElements: 'RelatingStructure', | ||
ReferencesElements: 'RelatingStructure', HasCoverings: 'RelatingSpace', BoundedBy: 'RelatingSpace'] | ||
related.each {k, v -> | ||
space[k + '_Inverse'].collect {it}.each { | ||
it.invokeMethod('remove' + v, space) | ||
if (it[v].isEmpty()) ifcModel.removeIfcObject(it) | ||
} | ||
} | ||
relating.each {k, v -> | ||
def rel = space[k + '_Inverse'] | ||
if (rel) ifcModel.removeIfcObject(rel) | ||
} | ||
ifcModel.removeIfcObject(space) | ||
} | ||
|
||
} |