fml 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ fml2dae_cache
1
2
  *.swp
2
3
  *.fml
3
4
  *~
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+
2
+ * Get rid of project FML stuff, and handle only design FML
data/bin/fml2dae.rb CHANGED
@@ -3,13 +3,18 @@ $: << File.join(File.dirname(__FILE__), "/../lib" )
3
3
  require 'floorplanner'
4
4
 
5
5
  if ARGV.length < 2
6
- puts "\n Usage: fml2dae.rb [-xrefs] design_id|design_name path/to/fml out.dae"
7
- else
8
- xrefs = false
9
- if ARGV[0] == "-xrefs"
10
- ARGV.shift
11
- xrefs = true
12
- end
13
- doc = Floorplanner::Document.new(ARGV[1])
14
- doc.to_dae(ARGV[0],ARGV[2],xrefs)
6
+ puts "\n Usage: fml2dae.rb [-xrefs] path/to/fml out.dae"
7
+ exit
15
8
  end
9
+
10
+ conf = {
11
+ :ceiling => false,
12
+ :window_glass => true
13
+ }
14
+
15
+ if ARGV[0] == "-xrefs"
16
+ ARGV.shift
17
+ conf[:xrefs] = true
18
+ end
19
+ doc = Floorplanner::XML::Document.from_xml(open(ARGV[0]))
20
+ doc.to_dae(ARGV[1], conf)
data/fml.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "fml"
5
- s.version = "0.2.3"
6
- s.date = "2010-05-18"
5
+ s.version = "0.2.4"
6
+ s.date = "2010-11-25"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 1.3.0") if s.respond_to? :required_rubygems_version=
9
9
 
10
10
  s.authors = ["Dusan Maliarik"]
11
11
  s.description = %q{Floor plan document toolkit}
12
12
  s.email = %q{dusan.maliarik@gmail.com}
13
- s.executables = ["fml2dae.rb","fml2obj.rb"]
14
- s.files = %w(lib/keyhole/archive.rb lib/floorplanner/opening3d.rb bin/fml2dae.rb xml/fml2kml.xsl xml/fml.rng xml/collada_schema_1_4.xsd lib/floorplanner/design.rb lib/floorplanner/collada_export.rb views/design.dae.erb lib/geom/plane.rb lib/geom.rb lib/floorplanner/area_builder.rb lib/config.yml .gitignore lib/geom/intersection.rb lib/geom/ear_trim.rb lib/geom/connection.rb lib/floorplanner.rb fml.gemspec lib/geom/polygon.rb lib/geom/edge.rb lib/floorplanner/asset.rb views/design.rib.erb lib/geom/matrix3d.rb lib/floorplanner/rib_export.rb lib/floorplanner/obj_export.rb Rakefile README views/design.obj.erb lib/geom/triangle.rb lib/geom/triangle_mesh.rb lib/floorplanner/wall_builder.rb lib/floorplanner/svg_export.rb lib/collada/geometry.rb views/design.svg.erb tasks/github-gem.rake lib/geom/vertex.rb lib/geom/glu_tess.rb lib/floorplanner/wall3d.rb lib/floorplanner/document.rb bin/fml2obj.rb lib/geom/number.rb lib/collada/document.rb)
13
+ s.executables = ["fml2dae.rb"]
14
+ s.files = %w(.gitignore README Rakefile TODO bin/fml2dae.rb fml.gemspec lib/collada/document.rb lib/collada/geometry.rb lib/config.yml lib/floorplanner.rb lib/floorplanner/area_builder.rb lib/floorplanner/asset.rb lib/floorplanner/collada_export.rb lib/floorplanner/design.rb lib/floorplanner/document.rb lib/floorplanner/opening3d.rb lib/floorplanner/svg_export.rb lib/floorplanner/wall3d.rb lib/floorplanner/wall_builder.rb lib/floorplanner/xml.rb lib/geom.rb lib/geom/connection.rb lib/geom/ear_trim.rb lib/geom/edge.rb lib/geom/glu_tess.rb lib/geom/intersection.rb lib/geom/matrix3d.rb lib/geom/number.rb lib/geom/plane.rb lib/geom/polygon.rb lib/geom/triangle.rb lib/geom/triangle_mesh.rb lib/geom/vertex.rb lib/keyhole/archive.rb tasks/github-gem.rake views/design.dae.erb views/design.svg.erb xml/collada_schema_1_4.xsd xml/fml.rng xml/fml2kml.xsl)
15
15
  s.homepage = %q{http://floorplanner.com/}
16
16
  s.require_paths = ["lib"]
17
17
  s.rubygems_version = %q{1.3.1}
@@ -22,15 +22,18 @@ Gem::Specification.new do |s|
22
22
  s.specification_version = 2
23
23
 
24
24
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
25
- s.add_runtime_dependency(%q<libxml-ruby>)
25
+ s.add_runtime_dependency(%q<nokogiri>)
26
26
  s.add_runtime_dependency(%q<rubyzip>)
27
+ s.add_runtime_dependency(%q<roxml>)
27
28
  else
28
- s.add_dependency(%q<libxml-ruby>)
29
+ s.add_dependency(%q<nokogiri>)
29
30
  s.add_dependency(%q<rubyzip>)
31
+ s.add_dependency(%q<roxml>)
30
32
  end
31
33
  else
32
- s.add_dependency(%q<libxml-ruby>)
34
+ s.add_dependency(%q<nokogiri>)
33
35
  s.add_dependency(%q<rubyzip>)
36
+ s.add_dependency(%q<roxml>)
34
37
  end
35
38
  end
36
39
 
@@ -1,34 +1,32 @@
1
1
  require 'cgi'
2
2
 
3
3
  module Collada
4
- class Document < XML::Document
5
- XMLNS = "http://www.collada.org/2005/11/COLLADASchema"
6
- VERSION = "1.4.1"
4
+ class Document < Nokogiri::XML::Document
5
+ COLLADA_NS = "http://www.collada.org/2005/11/COLLADASchema"
6
+ COLLADA_VERSION = "1.4.1"
7
7
 
8
- COLLADA = 'COLLADA'
9
8
  ASSET = 'asset'
10
- LIBRARY_MATERIALS = 'library_materials'
11
- LIBRARY_EFFECTS = 'library_effects'
12
- LIBRARY_GEOMETRIES = 'library_geometries'
9
+ LIBRARY_MATERIALS = 'library_materials'
10
+ LIBRARY_EFFECTS = 'library_effects'
11
+ LIBRARY_GEOMETRIES = 'library_geometries'
13
12
  LIBRARY_VISUAL_SCENES = 'library_visual_scenes'
14
- SCENE = 'scene'
15
- VISUAL_SCENE = 'visual_scene'
13
+ SCENE = 'scene'
14
+ VISUAL_SCENE = 'visual_scene'
16
15
  INSTANCE_VISUAL_SCENE = 'instance_visual_scene'
17
16
 
18
17
  attr_accessor :assets_libraries
19
18
 
20
19
  def initialize
21
20
  super
22
- self.root = XML::Node.new(COLLADA)
23
- self.root.namespaces.namespace = XML::Namespace.new(self.root,nil,XMLNS)
24
- self.root.attributes['version'] = VERSION
21
+ root = create_element 'COLLADA'
22
+ root.namespace = COLLADA_NS
23
+ root.attr['version'] = COLLADA_VERSION
25
24
 
26
25
  create_structure
27
-
28
- self.assets_libraries = []
26
+ assets_libraries = []
29
27
  end
30
28
 
31
- def << (node)
29
+ def << node
32
30
  root << node
33
31
  end
34
32
 
@@ -51,18 +49,18 @@ module Collada
51
49
 
52
50
  private
53
51
  def create_structure
54
- self << XML::Node.new(ASSET)
52
+ self << create_element(ASSET)
55
53
 
56
- self << XML::Node.new(LIBRARY_MATERIALS)
57
- self << XML::Node.new(LIBRARY_EFFECTS)
58
- self << XML::Node.new(LIBRARY_GEOMETRIES)
59
- self << (visual_scenes = XML::Node.new(LIBRARY_VISUAL_SCENES))
60
- visual_scenes << (visual_scene = XML::Node.new(VISUAL_SCENE))
54
+ self << create_element(LIBRARY_MATERIALS)
55
+ self << create_element(LIBRARY_EFFECTS)
56
+ self << create_element(LIBRARY_GEOMETRIES)
57
+ self << (visual_scenes = create_element(LIBRARY_VISUAL_SCENES))
58
+ visual_scenes << (visual_scene = create_element(VISUAL_SCENE))
61
59
  visual_scene['id'] = 'MainScene'
62
60
  visual_scene['name'] = 'MainScene'
63
61
 
64
- self << (scene = XML::Node.new(SCENE))
65
- scene << (scene_node = XML::Node.new(INSTANCE_VISUAL_SCENE))
62
+ self << (scene = create_element(SCENE))
63
+ scene << (scene_node = create_element(INSTANCE_VISUAL_SCENE))
66
64
  scene_node['url'] = '#MainScene'
67
65
  end
68
66
 
@@ -6,14 +6,14 @@ module Collada
6
6
  GEOMETRY_QUERY = '/COLLADA/library_geometries/geometry[@id="%s"]'
7
7
  NODE_QUERY = '/COLLADA/library_nodes//node[@id="%s"]'
8
8
 
9
- def self.doc(xml)
9
+ def self.doc doc
10
10
  result = Geometry.new
11
11
  result.instance_eval do
12
- @xml = xml
12
+ @doc = doc
13
13
  @cache = {}
14
14
 
15
- scene_id = xml.find(SCENE_QUERY).first.attributes['url'][1..-1]
16
- scene = xml.find(VISUAL_SCENE_QUERY % scene_id).first
15
+ scene_id = @doc.xpath(SCENE_QUERY).first.attribute('url').value[1..-1]
16
+ scene = @doc.xpath(VISUAL_SCENE_QUERY % scene_id).first
17
17
  scene.children.each do |child|
18
18
  eval_node(child) if child.name == "node"
19
19
  end
@@ -23,7 +23,7 @@ module Collada
23
23
 
24
24
  private
25
25
 
26
- def eval_node(node,parent=nil)
26
+ def eval_node node, parent=nil
27
27
  parent = node.parent unless parent
28
28
  parent_matrix = Geom::Matrix3D.identity
29
29
  if parent.name == "node"
@@ -43,23 +43,22 @@ module Collada
43
43
  when "node"
44
44
  eval_node(child,node)
45
45
  when "instance_geometry"
46
- load_geometry(child.attributes['url'][1..-1],node_matrix)
46
+ load_geometry(child.attribute('url').value[1..-1],node_matrix)
47
47
  when "instance_node"
48
48
  eval_node(expand_node(child),node)
49
49
  end
50
50
  end
51
51
  end
52
52
 
53
- def load_geometry(gid,matrix=nil)
54
- geometry = @xml.find(GEOMETRY_QUERY % gid).first
53
+ def load_geometry gid, matrix=nil
54
+ geometry = @doc.xpath(GEOMETRY_QUERY % gid).first
55
55
  mesh = Geom::TriangleMesh.new
56
56
 
57
57
  floats = Array.new
58
- geometry.find('mesh/triangles').each do |triangles|
59
- vertices_id = triangles.find('input[@semantic="VERTEX"]').first.attributes['source'][1..-1]
60
- source_id = geometry.find('mesh/vertices[@id="%s"]/input[@semantic="POSITION"]' % vertices_id).first.attributes['source'][1..-1]
61
-
62
- floats.concat geometry.find('mesh/source[@id="%s"]/float_array' % source_id).first.get_floats
58
+ geometry.xpath('mesh/triangles').each do |triangles|
59
+ vertices_id = triangles.xpath('input[@semantic="VERTEX"]').first.attribute('source').value[1..-1]
60
+ source_id = geometry.xpath('mesh/vertices[@id="%s"]/input[@semantic="POSITION"]' % vertices_id).first.attribute('source').value[1..-1]
61
+ floats.concat geometry.xpath('mesh/source[@id="%s"]/float_array' % source_id).first.content.split.map(&:to_f)
63
62
  end
64
63
 
65
64
  (floats.length/3).times do |i|
@@ -71,36 +70,36 @@ module Collada
71
70
  @meshes << mesh
72
71
  end
73
72
 
74
- def expand_node(instance)
75
- node_id = instance.attributes['url'][1..-1]
76
- @xml.find(NODE_QUERY % node_id).first
73
+ def expand_node instance
74
+ node_id = instance.attribute('url').value[1..-1]
75
+ @doc.xpath(NODE_QUERY % node_id).first
77
76
  end
78
77
 
79
- def get_node_matrix(node,source=nil)
78
+ def get_node_matrix node, source=nil
80
79
  result = source ? source : Geom::Matrix3D.identity
81
80
  node.children.each do |child|
82
81
  case child.name
83
82
  when "translate"
84
83
  f = child.get_floats
85
84
  t = Geom::Matrix3D.translation(f[0],f[1],f[2])
86
- result = result.multiply(t)
85
+ result *= t
87
86
  when "scale"
88
87
  f = child.get_floats
89
88
  t = Geom::Matrix3D.scale(f[0],f[1],f[2])
90
- result = result.multiply(t)
89
+ result *= t
91
90
  when "rotate"
92
91
  f = child.get_floats
93
- t = Geom::Matrix3D.rotation_matrix(f[0],f[1],f[2],f[3])
94
- result = result.multiply(t)
92
+ t = Geom::Matrix3D.rotation(f[0],f[1],f[2],f[3])
93
+ result *= t
95
94
  when "matrix"
96
- f = child.get_floats
95
+ f = child.content.split.map(&:to_f)
97
96
  t = Geom::Matrix3D[
98
97
  [ *f[0..3] ],
99
98
  [ *f[4..7] ],
100
99
  [ *f[8..11] ],
101
100
  [ *f[12..15] ]
102
101
  ]
103
- result = result.multiply(t)
102
+ result *= t
104
103
  end
105
104
  end
106
105
  result
data/lib/config.yml CHANGED
@@ -1,13 +1,13 @@
1
1
  content_base_url: http://cdn.floorplanner.com/assets/
2
- dae_cache_path: /home/skrat/workspace/floorplanner/fml2dae_cache/
3
- area_textures_path: /home/skrat/workspace/floorplanner/fml2dae_cache/textures_2d/
2
+ dae_cache_path: fml2dae_cache/
3
+ area_textures_path: fml2dae_cache/textures_2d/
4
4
 
5
5
  geom_snap: 0.1
6
6
  uniq_snap: 0.0000005
7
7
  openings:
8
8
  window_base: 0.65
9
- window_height: 1.6
10
- door_height: 2.2
9
+ window_height: 1.5
10
+ door_height: 2.1
11
11
 
12
12
  svg:
13
13
  width: 1024
@@ -21,14 +21,9 @@ module Floorplanner
21
21
  end
22
22
  end
23
23
 
24
- HEX_RE = "(?i:[a-f\\d])"
25
- def area(vertices,params=nil)
26
- a_id = vertices.hash.abs.to_s + "_" +params[:type]
27
- if params[:color] =~ /\A#((?:#{HEX_RE}{2,2}){3,4})\z/
28
- params[:color] = [*$1.scan(/.{2,2}/).collect {|value| value.hex / 255.0}]
29
- else
30
- params[:color] = [1,1,1]
31
- end
24
+ def area(vertices, params=nil)
25
+ a_id = vertices.hash.abs.to_s + "_" + params[:type].to_s
26
+ params[:color] = Floorplanner.read_color params[:color]
32
27
  @meshes[a_id] = Geom::Polygon.new(vertices, nil, params.merge({:id => a_id}))
33
28
  end
34
29
 
@@ -1,5 +1,5 @@
1
1
  module Floorplanner
2
- class Asset
2
+ class DAE
3
3
  LIBRARY_GEOMETRIES = '/COLLADA/library_geometries/geometry'
4
4
  LIBRARY_EFFECTS = '/COLLADA/library_effects/effect'
5
5
  LIBRARY_MATERIALS = '/COLLADA/library_materials/material'
@@ -13,15 +13,15 @@ module Floorplanner
13
13
 
14
14
  attr_reader :id, :name, :title, :dae_path
15
15
 
16
- def self.get(asset_id,asset_title,asset_url3d)
16
+ def self.get(asset)
17
17
  FileUtils.mkdir_p(CACHE_PATH)
18
- asset_url = Floorplanner.config['content_base_url'] + URI.escape(asset_url3d)
18
+ asset_url = Floorplanner.config['content_base_url'] + URI.escape(asset.url3d)
19
19
 
20
- cached_path = File.join(CACHE_PATH,asset_id)
20
+ cached_path = File.join(CACHE_PATH, asset.id)
21
21
  if File.exists?(cached_path)
22
- $stderr.puts("Cached asset: %s" % asset_id)
22
+ $stderr.puts("Cached asset: %s" % asset.id)
23
23
  @kmz = Keyhole::Archive.new(cached_path)
24
- Asset.new(asset_id,asset_title,@kmz)
24
+ DAE.new(asset.id, asset.name, @kmz)
25
25
  else
26
26
  $stderr.puts("Downloading asset: %s" % asset_url)
27
27
  cached = File.new(cached_path,'w')
@@ -30,19 +30,24 @@ module Floorplanner
30
30
  cached.close
31
31
 
32
32
  @kmz = Keyhole::Archive.new(cached_path)
33
- asset = Asset.new(asset_id,asset_title,@kmz)
34
- asset.adjust_paths!
35
- asset
33
+ dae = DAE.new(asset.id, asset.name, @kmz)
34
+ dae.adjust_paths!
35
+ dae
36
36
  end
37
+ rescue
38
+ $stderr.puts "Failed to get asset: %s, %s" % [asset.id, asset_url]
39
+ raise
37
40
  end
38
41
 
39
- def initialize(id,title,kmz)
42
+ def initialize(id, title, kmz)
40
43
  @dae_path = kmz.dae_path(id)
41
44
  @kmz = kmz
42
45
  @id = id
43
46
  @title = title
44
- @xml = XML::Document.string(File.read(@dae_path).gsub(/xmlns=".+"/, ''))
45
47
  @name = File.basename(@dae_path.gsub(/\.|dae/,''))
48
+
49
+ @doc = Nokogiri::XML.parse(open(@dae_path))
50
+ @doc.remove_namespaces!
46
51
  @images_dict = {}
47
52
  end
48
53
 
@@ -51,46 +56,46 @@ module Floorplanner
51
56
 
52
57
  def library_materials
53
58
  return @materials if @materials
54
- materials = @xml.find(LIBRARY_MATERIALS)
59
+ materials = @doc.xpath(LIBRARY_MATERIALS)
55
60
  materials.each {|mat| namespace!(mat)}
56
61
  @materials = materials
57
62
  end
58
63
 
59
64
  def library_effects
60
65
  return @effects if @effects
61
- effects = @xml.find(LIBRARY_EFFECTS)
66
+ effects = @doc.xpath(LIBRARY_EFFECTS)
62
67
  effects.each {|eff| namespace!(eff)}
63
68
  @effects = effects
64
69
  end
65
70
 
66
71
  def library_geometries
67
72
  return @geometries if @geometries
68
- geometries = @xml.find(LIBRARY_GEOMETRIES)
73
+ geometries = @doc.xpath(LIBRARY_GEOMETRIES)
69
74
  geometries.each{|geo| namespace!(geo)}
70
75
  @geometries = geometries
71
76
  end
72
77
 
73
78
  def library_nodes
74
79
  return @nodes if @nodes
75
- nodes = @xml.find(LIBRARY_NODES)
80
+ nodes = @doc.xpath(LIBRARY_NODES)
76
81
  nodes.each{|nod| namespace!(nod)}
77
82
  @nodes = nodes
78
83
  end
79
84
 
80
85
  def library_images
81
86
  return @images if @images
82
- images = @xml.find(LIBRARY_IMAGES)
87
+ images = @doc.xpath(LIBRARY_IMAGES)
83
88
  images.each{|img| namespace!(img) && update_path!(img)}
84
89
  @images = images
85
90
  end
86
91
 
87
92
  def visual_scene_node
88
93
  return @scene_node if @scene_node
89
- @scene_node = namespace!(@xml.find(VISUAL_SCENE_QUERY).first)
94
+ @scene_node = namespace!(@doc.xpath(VISUAL_SCENE_QUERY).first)
90
95
  end
91
96
 
92
97
  def bounding_box
93
- mesh = Collada::Geometry.doc @xml
98
+ mesh = Collada::Geometry.doc @doc
94
99
  mesh.bounding_box
95
100
  end
96
101
 
@@ -115,11 +120,11 @@ module Floorplanner
115
120
  end
116
121
 
117
122
  def save_textures(root_path)
118
- images = @xml.find(LIBRARY_IMAGES)
119
- FileUtils.mkdir_p(root_path) unless images.length.zero?
123
+ images = @doc.xpath(LIBRARY_IMAGES)
124
+ FileUtils.mkdir_p(root_path)
120
125
 
121
126
  images.each do |image|
122
- relative_to_dae = image.find('init_from').first.content
127
+ relative_to_dae = image.xpath('init_from').first.content
123
128
  img_path = @kmz.image_path(@id,relative_to_dae)
124
129
  target_path = File.join(root_path,@id)
125
130
  FileUtils.mkdir_p target_path
@@ -132,15 +137,15 @@ module Floorplanner
132
137
  end
133
138
 
134
139
  def adjust_paths!
135
- images = @xml.find(LIBRARY_IMAGES)
140
+ images = @doc.xpath(LIBRARY_IMAGES)
136
141
 
137
142
  images.each do |image|
138
- init_from = image.find('init_from').first
143
+ init_from = image.xpath('init_from').first
139
144
  img_path = @kmz.image_path(@id,init_from.content,true)
140
145
  init_from.content = img_path
141
146
  end
142
147
  open(@dae_path, 'w') do |f|
143
- f.write @xml.to_s
148
+ f.write @doc.to_s
144
149
  end
145
150
  end
146
151
 
@@ -160,12 +165,12 @@ module Floorplanner
160
165
  node['texture'] = "#{@name}_#{node['texture'].gsub('#','')}" if node['texture']
161
166
 
162
167
  if node.name == 'surface'
163
- n = node.find('init_from').first
168
+ n = node.xpath('init_from').first
164
169
  n.content = "#{@name}_#{n.content}"
165
170
  end
166
171
 
167
172
  if node.name == 'sampler2D'
168
- n = node.find('source').first
173
+ n = node.xpath('source').first
169
174
  n.content = "#{@name}_#{n.content}"
170
175
  end
171
176
 
@@ -177,7 +182,7 @@ module Floorplanner
177
182
 
178
183
  # updates image path to export output folder
179
184
  def update_path!(node)
180
- init_from_node = node.find('init_from').first
185
+ init_from_node = node.xpath('init_from').first
181
186
  relative = init_from_node.content
182
187
  init_from_node.content = @images_dict[relative]
183
188
  end
@@ -1,32 +1,37 @@
1
- module Floorplanner
1
+ module Floorplanner::XML
2
2
  class Document
3
3
 
4
- def to_dae(design_id,out_path,xrefs=false)
5
- @design = Design.new(@xml,design_id)
4
+ def to_dae thing, conf={}
5
+ @design = Floorplanner::Design.new(self)
6
6
  @design.build_geometries
7
- @design.save_textures(File.dirname(out_path)) unless xrefs
8
- dae = File.new(out_path,'w')
9
- dae.write(@design.to_dae(xrefs))
10
- dae.close
7
+ if thing.kind_of? String
8
+ unless conf[:xrefs]
9
+ @design.save_textures(File.dirname(thing))
10
+ end
11
+ dae = File.new(thing,'w')
12
+ dae.write @design.to_dae(conf)
13
+ dae.close
14
+ elsif thing.respond_to? :write
15
+ thing.write @design.to_dae(conf)
16
+ end
11
17
  end
12
-
13
18
  end
19
+ end
14
20
 
21
+ module Floorplanner
15
22
  module ColladaExport
16
- DESIGN_QUERY = "/project/floors/floor/designs/design[id='%s']"
17
- ASSET_QUERY = DESIGN_QUERY+"/assets/asset[@id='%s']"
18
- ASSETS_QUERY = DESIGN_QUERY+"/assets/asset"
19
- OBJECTS_QUERY = DESIGN_QUERY+"/objects/object"
20
23
 
21
- def to_dae(xrefs=false)
22
- raise "No geometries to export. Call build_geometries first" unless @areas && @walls
24
+ CACHE_PATH = File.join(Floorplanner.config['dae_cache_path'], 'textures_2d')
25
+
26
+ def to_dae conf
27
+ raise "No geometries to export" unless @areas && @walls
23
28
  @assets = assets
24
29
  @elements = objects
25
30
 
26
31
  # somehow...
27
32
  @walls.reverse
28
33
  @areas.each {|a| a.reverse}
29
- @xrefs = xrefs
34
+ @conf = conf
30
35
 
31
36
  template = ERB.new(
32
37
  File.read(
@@ -37,82 +42,82 @@ module Floorplanner
37
42
  def assets
38
43
  return @assets if @assets
39
44
  @assets = {}
40
- @xml.find(ASSETS_QUERY % @design_id).each do |asset_node|
41
- asset_id = asset_node.attributes['id']
42
- name = asset_node.find('name').first.content
43
- url3d = asset_node.find('url3d').first
44
- next unless url3d
45
- url3d = url3d.content
45
+ @doc.assets.each do |asset|
46
+ next unless asset.url3d && !asset.url3d.empty?
46
47
 
47
48
  # TODO: store asset bounding box
48
- asset = Floorplanner::Asset.get(asset_id,name,url3d)
49
- next unless asset
50
- @assets.store(asset_id, asset)
49
+ dae = Floorplanner::DAE.get(asset)
50
+ next unless dae
51
+ @assets.store(asset.id, dae)
51
52
  end
52
53
  @assets
53
54
  end
54
55
 
55
56
  def objects
56
57
  result = []
57
- @xml.find(OBJECTS_QUERY % @design_id).each do |object|
58
- begin
59
- refid = object.find('asset').first.attributes['refid']
60
- next unless assets[refid]
61
-
62
- asset = assets[refid]
63
- position = Geom::Number3D.from_str(object.find('points').first.content)
64
- # correct Flash axis issues
65
- position.y *= -1.0
66
-
67
- # correct Flash rotation issues
68
- rotation = unless object.find('rotation').empty?
69
- object.find('rotation').first.content
70
- else
71
- '0 0 0'
72
- end
73
- rotation = Geom::Number3D.from_str(rotation)
74
- rotation.z += 360 if rotation.z < 0
75
- rotation.z += 180
76
-
77
- # find proper scale for object
78
- size = object.find('size').first.content
79
- scale = asset.scale_ratio(Geom::Number3D.from_str(size))
80
-
81
- mirrored = object.find('mirrored').first
82
- reflection = Geom::Matrix3D.reflection(Geom::Plane.new(Geom::Number3D.new(0.0,1.0,0.0), Geom::Number3D.new))
83
- if mirrored
84
- mirror = Geom::Number3D.from_str(mirrored)
85
- if mirror.x != 0 || mirror.y != 0 || mirror.z != 0
86
- mirror.x = mirror.x > 0 ? 1 : 0
87
- mirror.y = mirror.y > 0 ? 1 : 0
88
- mirror.z = mirror.z > 0 ? 1 : 0
89
-
90
- origin = Geom::Number3D.new
91
- plane = Geom::Plane.new(mirror,origin)
92
- reflection = Geom::Matrix3D.reflection(plane).multiply reflection
93
- end
58
+ @doc.objects.each do |item|
59
+ next unless assets[item.asset]
60
+ asset = assets[item.asset]
61
+
62
+ pos = item.position
63
+ rot = item.rotation || Geom::Number3D.new
64
+ scale = asset.scale_ratio(item.size)
65
+
66
+ if item.mirrored
67
+ m_mirror = Geom::Matrix3D.reflection(
68
+ Geom::Plane.new(item.mirrored, Geom::Number3D.new))
94
69
  end
95
70
 
71
+ m_scale = Geom::Matrix3D.scale(scale.x, scale.y, scale.z)
72
+ m_rotate = Geom::Matrix3D.rotation(0, 0, 1, (Math::PI/180)*rot.z)
73
+ m_translate = Geom::Matrix3D.translation(pos.x, pos.y, pos.z)
74
+
75
+ m_combined = m_rotate * m_scale
76
+ m_combined = m_mirror * m_combined if m_mirror
77
+ m_combined = m_translate * m_combined
78
+
96
79
  result << {
97
- :asset => asset,
98
- :position => position,
99
- :rotation => rotation,
100
- :scale => scale,
101
- :matrix => reflection
80
+ :asset => asset,
81
+ :matrix => m_combined,
82
+ :color => Floorplanner.read_color(item.color)
102
83
  }
103
- rescue
104
- # TODO: handle text
105
- end
106
84
  end
107
85
  result
108
86
  end
109
87
 
110
- def save_textures(root_path)
111
- img_path = File.join(root_path,'textures')
88
+ def save_textures root_path
89
+ img_path = File.join(root_path, 'textures')
112
90
  FileUtils.mkdir_p img_path
113
91
  assets.each_value do |asset|
114
92
  asset.save_textures img_path
115
93
  end
94
+
95
+ t2d_path = File.join(img_path, 'textures_2d')
96
+ FileUtils.mkdir_p t2d_path
97
+ @areas.each do |area|
98
+ next unless area.data[:texture]
99
+ texture_url = area.data[:texture]
100
+ fn = texture_url.match(/.*\/(.*)/)[1]
101
+ tex_path = File.join(t2d_path, fn)
102
+ area.data[:texture] = File.join('textures', 'textures_2d', fn)
103
+ next if File.exists?(tex_path)
104
+
105
+ FileUtils.mkdir_p CACHE_PATH
106
+ cached_path = File.join(CACHE_PATH, fn)
107
+ unless File.exists?(cached_path)
108
+ puts "Downloading texture: %s" % texture_url
109
+ begin
110
+ cached = File.new(cached_path, 'w')
111
+ remote = open(Floorplanner.config['content_base_url'] +
112
+ URI.escape(texture_url))
113
+ cached.write(remote.read)
114
+ cached.close
115
+ rescue
116
+ $stderr.puts "Error downloading texture: %s" % fn
117
+ end
118
+ end
119
+ FileUtils.cp(cached_path, tex_path)
120
+ end
116
121
  end
117
122
  end
118
123
  end