diff --git a/src/bt_ifcmanager/lib/lib_ifc/IfcSite_su.rb b/src/bt_ifcmanager/lib/lib_ifc/IfcSite_su.rb index 8e672bd..5e4bc3b 100644 --- a/src/bt_ifcmanager/lib/lib_ifc/IfcSite_su.rb +++ b/src/bt_ifcmanager/lib/lib_ifc/IfcSite_su.rb @@ -23,60 +23,85 @@ module BimTools module IfcSite_su + @reflatitude = nil + @reflongitude = nil + # add project location, if set in sketchup model # (!) north angle still missing? def set_latlong - if Sketchup.active_model.georeferenced? - local_point = Geom::Point3d.new([0, 0, 0]) - @latlong = Sketchup.active_model.point_to_latlong(local_point) + return unless Sketchup.active_model.georeferenced? + + local_point = Geom::Point3d.new([0, 0, 0]) + @latlong = Sketchup.active_model.point_to_latlong(local_point) + end + + def reflatitude=(values) + if valid_latlong_list?(values) + @reflatitude = values + else + puts 'Invalid reflatitude values' end end - def latitude - return lat_long_ifc(@latlong[1]) if @latlong + def reflongitude=(values) + if valid_latlong_list?(values) + @reflongitude = values + else + puts 'Invalid reflongitude values' + end end - def longtitude - return lat_long_ifc(@latlong[0]) if @latlong + def reflatitude + lat_long_ifc(@latlong[1]) if @latlong + end + + def reflongitude + lat_long_ifc(@latlong[0]) if @latlong end def elevation - return IfcManager::Types::IfcLengthMeasure.new(@ifc_model, @latlong[2]) if @latlong + IfcManager::Types::IfcLengthMeasure.new(@ifc_model, @latlong[2]) if @latlong + end + + private + + def valid_latlong_list?(values) + values.is_a?(Array) && values.all? { |v| v.is_a?(IfcCompoundPlaneAngleMeasure) } end # convert sketchup latlong coordinate (decimal) to IFC notation (degrees) def lat_long_ifc(coordinate) - if Sketchup.active_model.georeferenced? - d = coordinate.abs - neg_pos = (coordinate / d).to_int - - # degrees - i = d.to_int - deg = i * neg_pos - - # minutes - d -= i - d *= 60 - i = d.to_int - - min = i * neg_pos - - # seconds - d -= i - d *= 60 - i = d.to_int - sec = i * neg_pos - - # millionth-seconds - d -= i - d *= 1_000_000 - i = d.to_int - msec = i * neg_pos - - # (!) values should be Ifc INTEGER objects instead of Strings(!) - # (!) returned object should be of type IFC LIST instead of IFC SET - IfcManager::Types::List.new([deg.to_s, min.to_s, sec.to_s, msec.to_s]) - end + return unless Sketchup.active_model.georeferenced? + + d = coordinate.abs + neg_pos = (coordinate / d).to_int + + # degrees + i = d.to_int + deg = i * neg_pos + + # minutes + d -= i + d *= 60 + i = d.to_int + + min = i * neg_pos + + # seconds + d -= i + d *= 60 + i = d.to_int + sec = i * neg_pos + + # millionth-seconds + d -= i + d *= 1_000_000 + i = d.to_int + msec = i * neg_pos + + # (!) values should be Ifc INTEGER objects instead of Strings(!) + # (!) returned object should be of type IFC LIST instead of IFC SET + IfcManager::Types::List.new([deg.to_s, min.to_s, sec.to_s, msec.to_s]) end end end diff --git a/src/bt_ifcmanager/lib/lib_ifc/ifc_types.rb b/src/bt_ifcmanager/lib/lib_ifc/ifc_types.rb index d219726..97031f4 100644 --- a/src/bt_ifcmanager/lib/lib_ifc/ifc_types.rb +++ b/src/bt_ifcmanager/lib/lib_ifc/ifc_types.rb @@ -26,7 +26,6 @@ module BimTools module IfcManager module Types - # https://technical.buildingsmart.org/wp-content/uploads/2018/05/IFC2x-Model-Implementation-Guide-V2-0b.pdf # page 19 and 20 def self.replace_char(in_string) @@ -207,6 +206,49 @@ def true?(obj) # OR # ((SELF[1] <= 0) AND (SELF[2] <= 0) AND (SELF[3] <= 0) AND ((SIZEOF(SELF) = 3) OR (SELF[4] <= 0))); # END_TYPE; + class IfcCompoundPlaneAngleMeasure < BaseType + def initialize(ifc_model, values, long = false) + super(ifc_model, values, long) + @values = values.map(&:to_i) + validate! + end + + def step + val = @values.join(',') + val = add_long(val) if @long + val + end + + private + + def validate! + raise ArgumentError, 'List must have 3 or 4 integers' unless (3..4).include?(@values.size) + raise ArgumentError, 'Minutes must be in range' unless minutes_in_range? + raise ArgumentError, 'Seconds must be in range' unless seconds_in_range? + raise ArgumentError, 'Microseconds must be in range' unless microseconds_in_range? + raise ArgumentError, 'Sign must be consistent' unless consistent_sign? + end + + def minutes_in_range? + @values[1].abs < 60 + end + + def seconds_in_range? + @values[2].abs < 60 + end + + def microseconds_in_range? + @values.size == 3 || @values[3].abs < 1_000_000 + end + + def consistent_sign? + if @values[0] >= 0 + @values.all? { |v| v >= 0 } + else + @values.all? { |v| v <= 0 } + end + end + end # TYPE IfcContextDependentMeasure = REAL; # END_TYPE; @@ -923,7 +965,7 @@ class IfcVolumetricFlowRateMeasure < IfcReal # END_TYPE; class PEnum_ElementStatus - def initialize(ifc_model, value, long = true) + def initialize(_ifc_model, value, _long = true) @value = value end @@ -931,7 +973,6 @@ def step @value end end - end end end diff --git a/src/bt_ifcmanager/lib/lib_ifc/parse_xsd.rb b/src/bt_ifcmanager/lib/lib_ifc/parse_xsd.rb index d344262..f617007 100644 --- a/src/bt_ifcmanager/lib/lib_ifc/parse_xsd.rb +++ b/src/bt_ifcmanager/lib/lib_ifc/parse_xsd.rb @@ -60,6 +60,7 @@ class IfcXsdParser IfcRelDefinesByProperties IfcRelDefinesByType IfcRelContainedInSpatialStructure + IfcSite IfcSpatialStructureElement IfcStyledItem IfcTypeProduct @@ -241,6 +242,7 @@ def get_mixin(ifc_name) mixin_file = Pathname.new("#{PLUGIN_ROOT_PATH}/bt_ifcmanager/lib/lib_ifc/#{ifc_name}_su.rb") if mixin_file.exist? require_relative(mixin_file) + puts "loaded #{ifc_name}_su" return BimTools.const_get(ifc_name + '_su') end nil @@ -285,7 +287,6 @@ def create_ifc_class(ifc_name, ifc_object, ifc_objects) ifc_attributes = get_ifc_attributes(ifc_object, ifc_name) - if mixin && mixin.respond_to?(:required_attributes) ifc_attributes.concat(mixin.required_attributes) ifc_attributes.uniq!