topolys 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b3301fef0d27e3a430a205feac0bbe4560e8c58f8e5aee5a28290b74e67f204c
4
+ data.tar.gz: cce3dd8ea4e5a42dcf97cb98597dd6ebe05748dd2f70875981c83e04f6cd43b6
5
+ SHA512:
6
+ metadata.gz: 3e6e997e94b2694cb7730127cd9022655b697ef82686db58f6b867dc83f9ac9048a77a1c0db7d22dcefdd8847f5538184d8c40bae3edc30d2fc9bac2edfd1d05
7
+ data.tar.gz: 61df74ca36f463dcfac81c808c425420903a3ab3a313b9037fc1fb085ac698d65c830b19e9c87957a4f13909da6e5c798be78378a93ce692207fea2b07fe13a7
data/.gitattributes ADDED
@@ -0,0 +1,2 @@
1
+ * text=auto
2
+ *.rb text
@@ -0,0 +1,25 @@
1
+ name: Pull Request CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - master
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-18.04
11
+ strategy:
12
+ matrix:
13
+ ruby: [ '2.4', '2.5' ]
14
+ name: Ruby ${{ matrix.ruby }} Tests
15
+ steps:
16
+ - name: Check out repository
17
+ uses: actions/checkout@v2
18
+ - name: Set up Ruby
19
+ uses: actions/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - name: Run Tests
23
+ run: |
24
+ bundle update
25
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,37 @@
1
+ # rspec failure tracking
2
+ .rspec_status
3
+
4
+ /.bundle/
5
+ /.yardoc
6
+ /_yardoc/
7
+ /.ruby-version
8
+ /Gemfile.lock
9
+ /gems
10
+ /coverage/
11
+ /doc/
12
+ /html/
13
+ /pkg/
14
+ /spec/reports/
15
+ /spec/test/
16
+ /spec/files/*/
17
+ /tmp/
18
+ /test/
19
+ /lib/.rubocop*
20
+
21
+ # rspec failure tracking
22
+ .rspec_status
23
+
24
+ # Ignore IDE files
25
+ /.idea
26
+ *.rubocop-http*
27
+
28
+ # runner conf
29
+ runner.conf
30
+
31
+ # .DS_Store (Mac)
32
+ *.DS_Store
33
+
34
+ # graphviz files
35
+ /*.dot
36
+ /*.pdf
37
+ /*.json
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.2.5
7
+ before_install: gem install bundler -v 1.17.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in topolys.gemspec
6
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2021 Dan Macumber & Denis Bourgeois
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Topolys
2
+
3
+ Topolys is a Ruby gem based on the rigorous non-manifold topology class hierarchy used in the [Topologic](https://github.com/NonManifoldTopology/Topologic) project. More information about Topologic is available on the [Topologic website](https://topologic.app). This class hierarchy is well suited to the topology of zero thickness space boundaries commonly used in energy modeling as well as other applications. The Topolys gem is agnostic to specific applications. Current users of Topolys include:
4
+
5
+ - [Thermal Bridging & Derating (tbd)](https://github.com/rd2/tbd) is a library and OpenStudio Measure for thermally derating outside-facing opaque constructions (walls, roofs and exposed floors), based on major thermal bridges (balconies, corners, fenestration perimeters, and so on).
6
+ - [TopolysMeasures](https://github.com/automaticmagic/TopolysMeasures), includes proof of concept OpenStudio Measures with the potential to provide improved surface intersection and matching, checks if spaces are fully enclosed, or other new functionality.
7
+
8
+ ## Documentation
9
+
10
+ Topolys is very new and does not yet have formal user documentation. A set of initial design documents are available at https://github.com/automaticmagic/topolys/tree/master/design
11
+
12
+ ## Installation
13
+
14
+ (revise) Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'topolys', github: 'automaticmagic/topolys', branch: 'master'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle update
23
+
24
+ ## Development
25
+
26
+ To run unit tests:
27
+
28
+ bundle exec rake
29
+
30
+ ## Contributing
31
+
32
+ Bug reports and pull requests are welcome on GitHub at https://github.com/automaticmagic/topolys.
33
+
34
+ ## License
35
+
36
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "topolys"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
Binary file
@@ -0,0 +1,351 @@
1
+ module Topolys
2
+
3
+ # Point3D, Vector3D, and Plane3D represents the 3D position and orientation
4
+ # of geometry in Topolys. Geometry is separate from topology (connections).
5
+
6
+ class Point3D
7
+
8
+ # @return [Float] X, Y, or Z coordinate
9
+ attr_reader :x, :y, :z
10
+
11
+ ##
12
+ # Initializes a Point3D object
13
+ #
14
+ # @param [Float] X-coordinate
15
+ # @param [Float] Y-coordinate
16
+ # @param [Float] Z-coordinate
17
+ def initialize(x, y, z)
18
+ raise "Incorrect x argument for Point3D, expected Numeric but got #{x.class}" unless x.is_a?(Numeric)
19
+ raise "Incorrect y argument for Point3D, expected Numeric but got #{y.class}" unless y.is_a?(Numeric)
20
+ raise "Incorrect z argument for Point3D, expected Numeric but got #{z.class}" unless z.is_a?(Numeric)
21
+ @x = x
22
+ @y = y
23
+ @z = z
24
+ end
25
+
26
+ def to_s
27
+ "[#{@x}, #{@y}, #{@z}]"
28
+ end
29
+
30
+ ##
31
+ # Adds a 3D vector to self
32
+ #
33
+ # @param [Vector3D] vector A Vector3D
34
+ #
35
+ # @return [Point3D] Returns a new Point3D - nil if vector not a Vector3D
36
+ def +(vector)
37
+ return nil unless vector.is_a?(Topolys::Vector3D)
38
+ x = @x + vector.x
39
+ y = @y + vector.y
40
+ z = @z + vector.z
41
+ return Topolys::Point3D.new(x, y, z)
42
+ end
43
+
44
+ ##
45
+ # Generates a 3D vector which goes from other to self
46
+ #
47
+ # @param [Point3D] other Another 3D point
48
+ #
49
+ # @return [Vector3D] Returns a new Vector3D - nil if other not a Point3D
50
+ def -(other)
51
+ return nil unless other.is_a?(Topolys::Point3D)
52
+ x = @x - other.x
53
+ y = @y - other.y
54
+ z = @z - other.z
55
+ return Topolys::Vector3D.new(x, y, z)
56
+ end
57
+
58
+ end # Point3D
59
+
60
+ class Vector3D
61
+
62
+ # @return [Float] X, Y, or Z component
63
+ attr_reader :x, :y, :z
64
+
65
+ ##
66
+ # Initializes a Vector3D object
67
+ #
68
+ # @param [Float] X-coordinate
69
+ # @param [Float] Y-coordinate
70
+ # @param [Float] Z-coordinate
71
+ def initialize(x, y, z)
72
+ raise "Incorrect x argument for Vector3D, expected Numeric but got #{x.class}" unless x.is_a?(Numeric)
73
+ raise "Incorrect y argument for Vector3D, expected Numeric but got #{y.class}" unless y.is_a?(Numeric)
74
+ raise "Incorrect z argument for Vector3D, expected Numeric but got #{z.class}" unless z.is_a?(Numeric)
75
+ @x = x
76
+ @y = y
77
+ @z = z
78
+ end
79
+
80
+ def to_s
81
+ "[#{@x}, #{@y}, #{@z}]"
82
+ end
83
+
84
+ def Vector3D.x_axis
85
+ Vector3D.new(1,0,0)
86
+ end
87
+
88
+ def Vector3D.y_axis
89
+ Vector3D.new(0,1,0)
90
+ end
91
+
92
+ def Vector3D.z_axis
93
+ Vector3D.new(0,0,1)
94
+ end
95
+
96
+ ##
97
+ # Adds 2x 3D vectors - overrides '+' operator
98
+ #
99
+ # @param [Vector3D] other Another 3D vector
100
+ #
101
+ # @return [Vector3D] Returns a new 3D resultant vector - nil if not Vector3D objects
102
+ def +(other)
103
+ return nil unless other.is_a?(Topolys::Vector3D)
104
+ x = @x + other.x
105
+ y = @y + other.y
106
+ z = @z + other.z
107
+ return Topolys::Vector3D.new(x, y, z)
108
+ end
109
+
110
+ ##
111
+ # Subtracts a 3D vector from another 3D vector - overrides '-' operator.
112
+ # Leaves original 3D vector intact if other is not a Vector3D object
113
+ #
114
+ # @param [Vector3D] other Another 3D vector
115
+ #
116
+ # @return [Vector3D] Returns a new 3D resultant vector - nil if not Vector3D objects
117
+ def -(other)
118
+ return nil unless other.is_a?(Topolys::Vector3D)
119
+ x = @x - other.x
120
+ y = @y - other.y
121
+ z = @z - other.z
122
+ return Topolys::Vector3D.new(x, y, z)
123
+ end
124
+
125
+ ##
126
+ # Multiplies a 3D vector by a scalar
127
+ #
128
+ # @param [Float] scalar A scalar
129
+ #
130
+ # @return [Vector3D] Returns a new, scaled 3D vector - nil if not numeric
131
+ def *(scalar)
132
+ return nil unless scalar.is_a?(Numeric)
133
+ x = @x * scalar
134
+ y = @y * scalar
135
+ z = @z * scalar
136
+ return Topolys::Vector3D.new(x, y, z)
137
+ end
138
+
139
+ ##
140
+ # Divides a 3D vector by a non-zero scalar
141
+ #
142
+ # @param [Float] scalar A non-zero scalar
143
+ #
144
+ # @return [Vector3D] Returns a new, scaled 3D vector - nil if 0 or not numeric
145
+ def /(scalar)
146
+ return nil unless scalar.is_a?(Numeric)
147
+ return nil if scalar.zero?
148
+ x = @x / scalar
149
+ y = @y / scalar
150
+ z = @z / scalar
151
+ Topolys::Vector3D.new(x, y, z)
152
+ end
153
+
154
+ ##
155
+ # Gets 3D vector magnitude (or length)
156
+ #
157
+ # @return [Float] Returns magnitude of the 3D vector
158
+ def magnitude
159
+ Math.sqrt(@x**2 + @y**2 + @z**2)
160
+ end
161
+
162
+ ##
163
+ # Normalizes a 3D vector
164
+ def normalize!
165
+ n = magnitude
166
+ unless n.zero?
167
+ @x /= n
168
+ @y /= n
169
+ @z /= n
170
+ end
171
+ end
172
+
173
+ ##
174
+ # Gets the dot (or inner) product of self & another 3D vector
175
+ #
176
+ # @param [Vector3D] other Another 3D vector
177
+ #
178
+ # @return [Float] Returns dot product - nil if not Vector3D objects
179
+ def dot(other)
180
+ return nil unless other.is_a?(Topolys::Vector3D)
181
+ return @x * other.x + @y * other.y + @z * other.z
182
+ end
183
+
184
+ ##
185
+ # Gets the cross product between self & another 3D vector
186
+ #
187
+ # @param [Vector3D] other Another 3D vector
188
+ #
189
+ # @return [Vector3D] Returns cross product - nil if not Vector3D objects
190
+ def cross(other)
191
+ return nil unless other.is_a?(Topolys::Vector3D)
192
+ x = @y * other.z - @z * other.y
193
+ y = @z * other.x - @x * other.z
194
+ z = @x * other.y - @y * other.x
195
+ return Topolys::Vector3D.new(x, y, z)
196
+ end
197
+
198
+ ##
199
+ # Gets the outer product between self & another 3D vector
200
+ #
201
+ # @param [Vector3D] other Another 3D vector
202
+ #
203
+ # @return [Matrix] Returns outer product
204
+ def outer_product(other)
205
+ return nil unless other.is_a?(Topolys::Vector3D)
206
+ result = Matrix.zero(3,3)
207
+ result[0,0] = @x*other.x
208
+ result[0,1] = @x*other.y
209
+ result[0,2] = @x*other.z
210
+ result[1,0] = @y*other.x
211
+ result[1,1] = @y*other.y
212
+ result[1,2] = @y*other.z
213
+ result[2,0] = @z*other.x
214
+ result[2,1] = @z*other.y
215
+ result[2,2] = @z*other.z
216
+ return result
217
+ end
218
+
219
+ ##
220
+ # Gets angle [0,PI) between self & another 3D vector
221
+ #
222
+ # @param [Vector3D] other Another 3D vector
223
+ #
224
+ # @return [Float] Returns angle - nil if not Vector3D objects
225
+ def angle(other)
226
+ return nil unless other.is_a?(Topolys::Vector3D)
227
+ prod = magnitude * other.magnitude
228
+ return nil if prod.zero?
229
+ val = dot(other) / prod
230
+ val = [-1.0, val].max
231
+ val = [ val, 1.0].min
232
+ Math.acos(val)
233
+ end
234
+
235
+ end # Vector3D
236
+
237
+ class Plane3D
238
+
239
+ # @return [Point3D] arbitrary point on plane
240
+ attr_reader :point
241
+
242
+ # @return [Vector3D] normalized vector perpendicular to plane
243
+ attr_reader :normal
244
+
245
+ ##
246
+ # Initializes a Plane3D object from a point and an outward normal
247
+ #
248
+ # @param [Point3d] point
249
+ # @param [Vector3D] normal
250
+ def initialize(point, normal)
251
+ raise "Incorrect point argument for Plane3D, expected Point3D but got #{point.class}" unless point.is_a?(Topolys::Point3D)
252
+ raise "Incorrect normal argument for Plane3D, expected Vector3D but got #{normal.class}" unless normal.is_a?(Topolys::Vector3D)
253
+ raise "Incorrect normal argument for Plane3D, magnitude too small" unless normal.magnitude > Float::EPSILON
254
+
255
+ @point = Point3D.new(point.x, point.y, point.z)
256
+ @normal = Vector3D.new(normal.x, normal.y, normal.z)
257
+ @normal.normalize!
258
+
259
+ # coefficients for equation of a plane
260
+ @a = @normal.x
261
+ @b = @normal.y
262
+ @c = @normal.z
263
+ @d = -(@a*@point.x + @b*@point.y + @c*@point.z)
264
+ end
265
+
266
+ def to_s
267
+ "[#{@a}, #{@b}, #{@c}, #{@d}]"
268
+ end
269
+
270
+ ##
271
+ # Initializes a Plane3D object from three non-colinear points
272
+ #
273
+ # @param [Point3d] point1
274
+ # @param [Point3d] point2
275
+ # @param [Point3d] point3
276
+ def Plane3D.from_points(point1, point2, point3)
277
+ return nil unless point1.is_a?(Topolys::Point3D)
278
+ return nil unless point2.is_a?(Topolys::Point3D)
279
+ return nil unless point3.is_a?(Topolys::Point3D)
280
+
281
+ normal = (point2-point1).cross(point3-point1)
282
+ return nil unless normal.magnitude > Float::EPSILON
283
+
284
+ return Plane3D.new(point1, normal)
285
+ end
286
+
287
+ ##
288
+ # Initializes a Plane3D object from a point and two vectors
289
+ #
290
+ # @param [Point3d] point
291
+ # @param [Vector3D] xaxis
292
+ # @param [Vector3D] yaxis
293
+ def Plane3D.from_point_axes(point, xaxis, yaxis)
294
+ return nil unless point.is_a?(Topolys::Point3D)
295
+ return nil unless xaxis.is_a?(Topolys::Vector3D)
296
+ return nil unless yaxis.is_a?(Topolys::Vector3D)
297
+
298
+ normal = xaxis.cross(yaxis)
299
+ return nil unless normal.magnitude > Float::EPSILON
300
+
301
+ return Plane3D.new(point, normal)
302
+ end
303
+
304
+ # TODO: implement methods below
305
+
306
+ ##
307
+ # Project a Point3d to this plane
308
+ #
309
+ # @param [Point3d] point
310
+ #
311
+ # @return [Point3d] Returns point projected to this plane
312
+ def project(point)
313
+ dist = @normal.dot(point-@point)
314
+ return point + normal*(-dist)
315
+ end
316
+
317
+ end # Plane3D
318
+
319
+ class BoundingBox
320
+
321
+ attr_reader :minx, :maxx, :miny, :maxy, :minz, :maxz
322
+
323
+ def initialize(tol = 0.001)
324
+ @tol = tol
325
+ @minx = Float::INFINITY
326
+ @miny = Float::INFINITY
327
+ @minz = Float::INFINITY
328
+ @maxx = -Float::INFINITY
329
+ @maxy = -Float::INFINITY
330
+ @maxz = -Float::INFINITY
331
+ end
332
+
333
+ def add_point(point)
334
+ @minx = [point.x, @minx].min
335
+ @miny = [point.y, @miny].min
336
+ @minz = [point.z, @minz].min
337
+ @maxx = [point.x, @maxx].max
338
+ @maxy = [point.y, @maxy].max
339
+ @maxz = [point.z, @maxz].max
340
+ end
341
+
342
+ def include?(point)
343
+ result = ((point.x >= @minx - @tol) && (point.x <= @maxx + @tol)) &&
344
+ ((point.y >= @miny - @tol) && (point.y <= @maxy + @tol)) &&
345
+ ((point.z >= @minz - @tol) && (point.z <= @maxz + @tol))
346
+ return result
347
+ end
348
+
349
+ end # BoundingBox
350
+
351
+ end # TOPOLYS