|
23 | 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | 24 | # SOFTWARE. |
25 | 25 |
|
26 | | -def toLowerCamelcase(string): |
27 | | - """Convert string from upper to lower camelCase""" |
| 26 | +import ifcopenshell |
| 27 | +import ifcopenshell.guid as guid |
28 | 28 |
|
29 | | - return string[0].lower() + string[1:] |
30 | 29 |
|
| 30 | +class IFC2JSON: |
| 31 | + """Base class for all IFC SPF to IFC.JSON writers |
| 32 | + """ |
31 | 33 |
|
32 | | -def createReferenceObject(objectDict, compact=False): |
33 | | - """Returns value for referenced object""" |
34 | | - ref = {} |
35 | | - if not compact: |
36 | | - ref['type'] = objectDict['type'] |
37 | | - ref['ref'] = objectDict['globalId'] |
38 | | - return ref |
| 34 | + DIMENSIONALEXPONENTS = { |
| 35 | + 'METRE': (1, 0, 0, 0, 0, 0, 0), |
| 36 | + 'SQUARE_METRE': (2, 0, 0, 0, 0, 0, 0), |
| 37 | + 'CUBIC_METRE': (3, 0, 0, 0, 0, 0, 0), |
| 38 | + 'GRAM': (0, 1, 0, 0, 0, 0, 0), |
| 39 | + 'SECOND': (0, 0, 1, 0, 0, 0, 0), |
| 40 | + 'AMPERE': (0, 0, 0, 1, 0, 0, 0), |
| 41 | + 'KELVIN': (0, 0, 0, 0, 1, 0, 0), |
| 42 | + 'MOLE': (0, 0, 0, 0, 0, 1, 0), |
| 43 | + 'CANDELA': (0, 0, 0, 0, 0, 0, 1), |
| 44 | + 'RADIAN': (0, 0, 0, 0, 0, 0, 0), |
| 45 | + 'STERADIAN': (0, 0, 0, 0, 0, 0, 0), |
| 46 | + 'HERTZ': (0, 0, -1, 0, 0, 0, 0), |
| 47 | + 'NEWTON': (1, 1, -2, 0, 0, 0, 0), |
| 48 | + 'PASCAL': (-1, 1, -2, 0, 0, 0, 0), |
| 49 | + 'JOULE': (2, 1, -2, 0, 0, 0, 0), |
| 50 | + 'WATT': (2, 1, -3, 0, 0, 0, 0), |
| 51 | + 'COULOMB': (0, 0, 1, 1, 0, 0, 0), |
| 52 | + 'VOLT': (2, 1, -3, -1, 0, 0, 0), |
| 53 | + 'FARAD': (-2, -1, 4, 2, 0, 0, 0), |
| 54 | + 'OHM': (2, 1, -3, -2, 0, 0, 0), |
| 55 | + 'SIEMENS': (-2, -1, 3, 2, 0, 0, 0), |
| 56 | + 'WEBER': (2, 1, -2, -1, 0, 0, 0), |
| 57 | + 'TESLA': (0, 1, -2, -1, 0, 0, 0), |
| 58 | + 'HENRY': (2, 1, -2, -2, 0, 0, 0), |
| 59 | + 'DEGREE_CELSIUS': (0, 0, 0, 0, 1, 0, 0), |
| 60 | + 'LUMEN': (0, 0, 0, 0, 0, 0, 1), |
| 61 | + 'LUX': (-2, 0, 0, 0, 0, 0, 1), |
| 62 | + 'BECQUEREL': (0, 0, -1, 0, 0, 0, 0), |
| 63 | + 'GRAY': (2, 0, -2, 0, 0, 0, 0), |
| 64 | + 'SIEVERT': (2, 0, -2, 0, 0, 0, 0), |
| 65 | + 'OTHERWISE': (0, 0, 0, 0, 0, 0, 0) |
| 66 | + } |
39 | 67 |
|
40 | | - # More compact alternative |
41 | | - # return objectDict['globalId'] |
| 68 | + def toLowerCamelcase(self, string): |
| 69 | + """Convert string from upper to lower camelCase""" |
| 70 | + |
| 71 | + return string[0].lower() + string[1:] |
| 72 | + |
| 73 | + def getDimensionsForSiUnit(self, entity): |
| 74 | + dimensions = {} |
| 75 | + if entity.Name in self.DIMENSIONALEXPONENTS: |
| 76 | + dimExps = self.DIMENSIONALEXPONENTS[entity.Name] |
| 77 | + if dimExps[0] != 0: |
| 78 | + dimensions['LengthExponent'] = dimExps[0] |
| 79 | + if dimExps[1] != 0: |
| 80 | + dimensions['MassExponent'] = dimExps[1] |
| 81 | + if dimExps[2] != 0: |
| 82 | + dimensions['TimeExponent'] = dimExps[2] |
| 83 | + if dimExps[3] != 0: |
| 84 | + dimensions['ElectricCurrentExponent'] = dimExps[3] |
| 85 | + if dimExps[4] != 0: |
| 86 | + dimensions['ThermodynamicTemperatureExponent'] = dimExps[4] |
| 87 | + if dimExps[5] != 0: |
| 88 | + dimensions['AmountOfSubstanceExponent'] = dimExps[5] |
| 89 | + if dimExps[6] != 0: |
| 90 | + dimensions['LuminousIntensityExponent'] = dimExps[6] |
| 91 | + |
| 92 | + return dimensions |
| 93 | + |
| 94 | + def getAttributeValue(self, value): |
| 95 | + """Recursive method that walks through all nested objects of an attribute |
| 96 | + and returns a IFC.JSON-4 model structure |
| 97 | +
|
| 98 | + Parameters: |
| 99 | + value |
| 100 | +
|
| 101 | + Returns: |
| 102 | + attribute data converted to IFC.JSON-4 model structure |
| 103 | +
|
| 104 | + """ |
| 105 | + if value == None or value == '': |
| 106 | + jsonValue = None |
| 107 | + elif isinstance(value, ifcopenshell.entity_instance): |
| 108 | + entity = value |
| 109 | + entityAttributes = entity.__dict__ |
| 110 | + |
| 111 | + # Remove empty properties |
| 112 | + if entity.is_a() == 'IfcPropertySingleValue': |
| 113 | + try: |
| 114 | + value = entity.NominalValue.wrappedValue |
| 115 | + if not value: |
| 116 | + return None |
| 117 | + except: |
| 118 | + return None |
| 119 | + |
| 120 | + # Add unit dimensions https://standards.buildingsmart.org/IFC/DEV/IFC4_2/FINAL/HTML/schema/ifcmeasureresource/lexical/ifcdimensionsforsiunit.htm |
| 121 | + if entity.is_a() == 'IfcSIUnit': |
| 122 | + entityAttributes['dimensions'] = self.getDimensionsForSiUnit( |
| 123 | + entity) |
| 124 | + |
| 125 | + # All objects with a GlobalId must be referenced, all others nested |
| 126 | + if entity.id() in self.rootobjects: |
| 127 | + entityAttributes["GlobalId"] = self.rootobjects[entity.id()] |
| 128 | + return self.createReferenceObject(entityAttributes, self.compact) |
| 129 | + else: |
| 130 | + if 'GlobalId' in entityAttributes: |
| 131 | + entityAttributes["GlobalId"] = guid.split( |
| 132 | + guid.expand(entity.GlobalId))[1:-1] |
| 133 | + |
| 134 | + return self.createFullObject(entityAttributes) |
| 135 | + elif isinstance(value, tuple): |
| 136 | + jsonValue = None |
| 137 | + subEnts = [] |
| 138 | + for subEntity in value: |
| 139 | + attrValue = self.getAttributeValue(subEntity) |
| 140 | + if attrValue: |
| 141 | + subEnts.append(attrValue) |
| 142 | + jsonValue = subEnts |
| 143 | + else: |
| 144 | + jsonValue = value |
| 145 | + return jsonValue |
| 146 | + |
| 147 | + def createReferenceObject(self, entityAttributes, compact=False): |
| 148 | + """Returns object reference |
| 149 | +
|
| 150 | + Parameters: |
| 151 | + entityAttributes (dict): Dictionary of IFC object data |
| 152 | + compact (boolean): verbose or non verbose IFC.JSON-4 output |
| 153 | +
|
| 154 | + Returns: |
| 155 | + dict: object containing reference to another object |
| 156 | +
|
| 157 | + """ |
| 158 | + ref = {} |
| 159 | + if not compact: |
| 160 | + ref['type'] = entityAttributes['type'] |
| 161 | + ref['ref'] = entityAttributes['GlobalId'] |
| 162 | + return ref |
0 commit comments