fml 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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