Module: MSPhysics::Collision

Defined in:
RubyExtension/MSPhysics/collision.rb

Overview

Since:

  • 1.0.0

Constant Summary collapse

ENTITY_VALIDATION_PROC =

Since:

  • 1.0.0

Proc.new { |entity|
  next true if (!entity.is_a?(Sketchup::Group) && !entity.is_a?(Sketchup::ComponentInstance))
  entity.get_attribute('MSPhysics', 'Type', 'Body') == 'Body' && !entity.get_attribute('MSPhysics Body', 'Ignore')
}

Class Method Summary collapse

Class Method Details

.clear_cachevoid

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Call this every time prior to starting a new simulation and after finishing generating all collisions.

Since:

  • 1.0.0



20
21
22
23
24
25
# File 'RubyExtension/MSPhysics/collision.rb', line 20

def clear_cache
  @bb_cache.clear
  @convex_cache.clear
  @compound_cache.clear
  @mesh_cache.clear
end

.create(world, entity, shape_id, transformation = nil) ⇒ Integer

Create a physics collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • shape_id (Integer)

    Shape ID. See SHAPE_NAMES

  • transformation (Geom::Transformation, nil) (defaults to: nil)

    A local transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Since:

  • 1.0.0



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'RubyExtension/MSPhysics/collision.rb', line 55

def create(world, entity, shape_id, transformation = nil)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  case shape_id
    when 0
      create_null(world)
    when 1
      create_box(world, entity, transformation)
    when 2
      create_sphere(world, entity, transformation)
    when 3
      create_cone(world, entity,transformation)
    when 4
      create_cylinder(world, entity, transformation)
    when 5
      create_chamfer_cylinder(world, entity, transformation)
    when 6
      create_capsule(world, entity, transformation)
    when 7
      create_convex_hull(world, entity, false)
    when 8
      create_compound2(world, entity)
    when 9
      create_static_mesh2(world, entity)
  else
    raise(TypeError, "The given shape ID, \"#{shape_id}\", does not reference a valid shape!", caller)
  end
end

.create_box(world, entity, transformation) ⇒ Integer

Create a box collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transformation (Geom::Transformation, nil)

    A transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if calculated bounding box turns out flat.

Since:

  • 1.0.0



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'RubyExtension/MSPhysics/collision.rb', line 99

def create_box(world, entity, transformation)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  bb = @bb_cache[definition]
  unless @bb_cache[definition]
    bb = AMS::Group.get_bounding_box_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @bb_cache[definition] = bb
  end
  if bb.width.to_f < MSPhysics::EPSILON || bb.height.to_f < MSPhysics::EPSILON || bb.depth.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has a flat bounding box. Flat collisions are invalid!", caller)
  end
  ent_tra = entity.transformation
  scale = AMS::Geometry.get_matrix_scale(ent_tra)
  center = bb.center
  center.x *= AMS::Geometry.is_matrix_flipped?(ent_tra) ? -scale.x : scale.x
  center.y *= scale.y
  center.z *= scale.z
  offset_matrix = Geom::Transformation.new(center)
  params = Geom::Vector3d.new(bb.width * scale.x, bb.height * scale.y, bb.depth * scale.z)
  if transformation
    offset_matrix = offset_matrix * transformation
    params.transform!(transformation)
  end
  MSPhysics::Newton::Collision.create_box(world.address, params.x.abs, params.y.abs, params.z.abs, 0, offset_matrix)
end

.create_capsule(world, entity, transformation) ⇒ Integer

Create a capsule collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transformation (Geom::Transformation, nil)

    A transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if calculated bounding box turns out flat.

Since:

  • 1.0.0



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'RubyExtension/MSPhysics/collision.rb', line 235

def create_capsule(world, entity, transformation)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  bb = @bb_cache[definition]
  unless @bb_cache[definition]
    bb = AMS::Group.get_bounding_box_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @bb_cache[definition] = bb
  end
  if bb.width.to_f < MSPhysics::EPSILON || bb.height.to_f < MSPhysics::EPSILON || bb.depth.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has a flat bounding box. Flat collisions are invalid!", caller)
  end
  ent_tra = entity.transformation
  scale = AMS::Geometry.get_matrix_scale(ent_tra)
  center = bb.center
  center.x *= AMS::Geometry.is_matrix_flipped?(ent_tra) ? -scale.x : scale.x
  center.y *= scale.y
  center.z *= scale.z
  offset_matrix = Geom::Transformation.new(center)
  params = Geom::Vector3d.new(bb.width * scale.x, bb.height * scale.y, bb.depth * scale.z)
  if transformation
    offset_matrix = offset_matrix * transformation
    params.transform!(transformation)
  end
  MSPhysics::Newton::Collision.create_scaled_capsule(world.address, params.z.abs * 0.5 , params.y.abs * 0.5, params.x.abs, 0, offset_matrix)
end

.create_chamfer_cylinder(world, entity, transformation) ⇒ Integer

Create a chamfer cylinder collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transformation (Geom::Transformation, nil)

    A transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if calculated bounding box turns out flat.

Since:

  • 1.0.0



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'RubyExtension/MSPhysics/collision.rb', line 269

def create_chamfer_cylinder(world, entity, transformation)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  bb = @bb_cache[definition]
  unless @bb_cache[definition]
    bb = AMS::Group.get_bounding_box_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @bb_cache[definition] = bb
  end
  if bb.width.to_f < MSPhysics::EPSILON || bb.height.to_f < MSPhysics::EPSILON || bb.depth.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has a flat bounding box. Flat collisions are invalid!", caller)
  end
  ent_tra = entity.transformation
  scale = AMS::Geometry.get_matrix_scale(ent_tra)
  center = bb.center
  center.x *= AMS::Geometry.is_matrix_flipped?(ent_tra) ? -scale.x : scale.x
  center.y *= scale.y
  center.z *= scale.z
  offset_matrix = Geom::Transformation.new(center)
  params = Geom::Vector3d.new(bb.width * scale.x, bb.height * scale.y, bb.depth * scale.z)
  if transformation
    offset_matrix = offset_matrix * transformation
    params.transform!(transformation)
  end
  MSPhysics::Newton::Collision.create_scaled_chamfer_cylinder(world.address, params.z.abs * 0.5 , params.y.abs * 0.5, params.x.abs, 0, offset_matrix)
end

.create_compound(world, entity) ⇒ Integer

Create a compound collision. In a compound collision every sub-group is considered a convex collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if entity doesn’t have any valid sub-collisions.

Since:

  • 1.0.0



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'RubyExtension/MSPhysics/collision.rb', line 343

def create_compound(world, entity)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  point_collections = @compound_cache[definition]
  unless @compound_cache[definition]
    point_collections = AMS::Group.get_vertices_from_faces2(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @compound_cache[definition] = point_collections
  end
  tra = entity.transformation
  s = AMS::Geometry.get_matrix_scale(tra)
  s.x *= -1 if AMS::Geometry.is_matrix_flipped?(tra)
  convex_collisions = []
  point_collections.each { |vertices|
    next if vertices.size < 4
    next if AMS::Geometry.points_coplanar?(vertices)
    vertices.each { |v|
      v.x *= s.x
      v.y *= s.y
      v.z *= s.z
    }
    sub_col = MSPhysics::Newton::Collision.create_convex_hull(world.address, vertices, 1.0e-4, 0, nil)
    convex_collisions << sub_col if sub_col
  }
  if convex_collisions.empty?
    raise(TypeError, "Entity #{entity} doesn't have any valid sub-collisions, making it an invalid compound collision!", caller)
  end
  collision = MSPhysics::Newton::Collision.create_compound(world.address, convex_collisions, 0)
  convex_collisions.each { |sub_col|
    MSPhysics::Newton::Collision.destroy(sub_col)
  }
  collision
end

.create_compound2(world, entity) ⇒ Integer

Create a compound collision. In a compound collision every sub-group is considered a convex collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if entity doesn’t have any valid sub-collisions.

Since:

  • 1.0.0



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'RubyExtension/MSPhysics/collision.rb', line 383

def create_compound2(world, entity)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  tra = entity.transformation
  s = AMS::Geometry.get_matrix_scale(tra)
  s.x *= -1 if AMS::Geometry.is_matrix_flipped?(tra)
  stra = Geom::Transformation.new([s.x,0,0,0, 0,s.y,0,0, 0,0,s.z,0, 0,0,0,1])
  meshes = AMS::Group.get_triangular_meshes(entity, true, stra, &ENTITY_VALIDATION_PROC)
  convex_collisions = []
  meshes.each { |mesh|
    vertices = mesh.points
    next if vertices.size < 4 || AMS::Geometry.points_coplanar?(vertices)
    sub_col = MSPhysics::Newton::Collision.create_convex_hull(world.address, vertices, 1.0e-4, 0, nil)
    convex_collisions << sub_col if sub_col
  }
  if convex_collisions.empty?
    raise(TypeError, "Entity #{entity} doesn't have any valid sub-collisions, making it an invalid compound collision!", caller)
  end
  collision = MSPhysics::Newton::Collision.create_compound(world.address, convex_collisions, 0)
  convex_collisions.each { |sub_col|
    MSPhysics::Newton::Collision.destroy(sub_col)
  }
  collision
end

.create_cone(world, entity, transformation) ⇒ Integer

Create a cone collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transformation (Geom::Transformation, nil)

    A transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if calculated bounding box turns out flat.

Since:

  • 1.0.0



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'RubyExtension/MSPhysics/collision.rb', line 167

def create_cone(world, entity, transformation)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  bb = @bb_cache[definition]
  unless @bb_cache[definition]
    bb = AMS::Group.get_bounding_box_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @bb_cache[definition] = bb
  end
  if bb.width.to_f < MSPhysics::EPSILON || bb.height.to_f < MSPhysics::EPSILON || bb.depth.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has a flat bounding box. Flat collisions are invalid!", caller)
  end
  ent_tra = entity.transformation
  scale = AMS::Geometry.get_matrix_scale(ent_tra)
  center = bb.center
  center.x *= AMS::Geometry.is_matrix_flipped?(ent_tra) ? -scale.x : scale.x
  center.y *= scale.y
  center.z *= scale.z
  offset_matrix = Geom::Transformation.new(center)
  params = Geom::Vector3d.new(bb.width * scale.x, bb.height * scale.y, bb.depth * scale.z)
  if transformation
    offset_matrix = offset_matrix * transformation
    params.transform!(transformation)
  end
  MSPhysics::Newton::Collision.create_scaled_cone(world.address, params.z.abs * 0.5 , params.y.abs * 0.5, params.x.abs, 0, offset_matrix)
end

.create_convex_hull(world, entity, transform = false) ⇒ Integer

Create a convex hull collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transform (Boolean) (defaults to: false)

    Whether to offset the collision. Usually this parameter is set true if the entity is a sub-collision of some parent collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if entity has too few vertices.

  • (TypeError)

    if entity has all vertices coplanar.

  • (TypeError)

    if the engine failed to generate convex hull.

Since:

  • 1.0.0



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'RubyExtension/MSPhysics/collision.rb', line 306

def create_convex_hull(world, entity, transform = false)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  vertices = @convex_cache[definition]
  unless @convex_cache[definition]
    vertices = AMS::Group.get_vertices_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @convex_cache[definition] = vertices
  end
  if vertices.size < 4
    raise(TypeError, "Entity #{entity} has too few vertices. At least four non-coplanar vertices are expected!", caller)
  end
  if AMS::Geometry.points_coplanar?(vertices)
    raise(TypeError, "Entity #{entity} has all vertices coplanar. Flat collisions are not acceptable!", caller)
  end
  tra = entity.transformation
  s = AMS::Geometry.get_matrix_scale(tra)
  s.x *= -1 if AMS::Geometry.is_matrix_flipped?(tra)
  vertices.each { |v|
    v.x *= s.x
    v.y *= s.y
    v.z *= s.z
  }
  offset_matrix = transform ? AMS::Geometry.extract_matrix_scale(tra) : nil
  collision = MSPhysics::Newton::Collision.create_convex_hull(world.address, vertices, 1.0e-4, 0, offset_matrix)
  unless collision
    raise(TypeError, "The engine failed to generate convex collision for entity, #{entity}, as the entity is probably too small!", caller)
  end
  collision
end

.create_cylinder(world, entity, transformation) ⇒ Integer

Create a cylinder collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transformation (Geom::Transformation, nil)

    A transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if calculated bounding box turns out flat.

Since:

  • 1.0.0



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'RubyExtension/MSPhysics/collision.rb', line 201

def create_cylinder(world, entity, transformation)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  bb = @bb_cache[definition]
  unless @bb_cache[definition]
    bb = AMS::Group.get_bounding_box_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @bb_cache[definition] = bb
  end
  if bb.width.to_f < MSPhysics::EPSILON || bb.height.to_f < MSPhysics::EPSILON || bb.depth.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has a flat bounding box. Flat collisions are invalid!", caller)
  end
  ent_tra = entity.transformation
  scale = AMS::Geometry.get_matrix_scale(ent_tra)
  center = bb.center
  center.x *= AMS::Geometry.is_matrix_flipped?(ent_tra) ? -scale.x : scale.x
  center.y *= scale.y
  center.z *= scale.z
  offset_matrix = Geom::Transformation.new(center)
  params = Geom::Vector3d.new(bb.width * scale.x, bb.height * scale.y, bb.depth * scale.z)
  if transformation
    offset_matrix = offset_matrix * transformation
    params.transform!(transformation)
  end
  MSPhysics::Newton::Collision.create_scaled_cylinder(world.address, params.z.abs * 0.5 , params.y.abs * 0.5, params.x.abs, 0, offset_matrix)
end

.create_null(world) ⇒ Integer

Create a null collision.

Parameters:

Returns:

  • (Integer)

    Collision address

Since:

  • 1.0.0



87
88
89
90
# File 'RubyExtension/MSPhysics/collision.rb', line 87

def create_null(world)
  MSPhysics::World.validate(world)
  MSPhysics::Newton::Collision.create_null(world.address)
end

.create_sphere(world, entity, transformation) ⇒ Integer

Create a sphere collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)
  • transformation (Geom::Transformation, nil)

    A transform to apply to the collision.

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if calculated bounding box turns out flat.

Since:

  • 1.0.0



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'RubyExtension/MSPhysics/collision.rb', line 133

def create_sphere(world, entity, transformation)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  bb = @bb_cache[definition]
  unless @bb_cache[definition]
    bb = AMS::Group.get_bounding_box_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @bb_cache[definition] = bb
  end
  if bb.width.to_f < MSPhysics::EPSILON || bb.height.to_f < MSPhysics::EPSILON || bb.depth.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has a flat bounding box. Flat collisions are invalid!", caller)
  end
  ent_tra = entity.transformation
  scale = AMS::Geometry.get_matrix_scale(ent_tra)
  center = bb.center
  center.x *= AMS::Geometry.is_matrix_flipped?(ent_tra) ? -scale.x : scale.x
  center.y *= scale.y
  center.z *= scale.z
  offset_matrix = Geom::Transformation.new(center)
  params = Geom::Vector3d.new(bb.width * scale.x, bb.height * scale.y, bb.depth * scale.z)
  if transformation
    offset_matrix = offset_matrix * transformation
    params.transform!(transformation)
  end
  MSPhysics::Newton::Collision.create_scaled_sphere(world.address, params.x.abs, params.y.abs, params.z.abs, 0, offset_matrix)
end

.create_static_mesh(world, entity) ⇒ Integer

Create a static tree/scene collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if entity has no faces.

Since:

  • 1.0.0



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'RubyExtension/MSPhysics/collision.rb', line 413

def create_static_mesh(world, entity)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  definition = AMS::Group.get_definition(entity)
  point_collections = @mesh_cache[definition]
  unless @mesh_cache[definition]
    triplets = AMS::Group.get_polygons_from_faces(entity, true, nil, &ENTITY_VALIDATION_PROC)
    @mesh_cache[definition] = triplets
  end
  if triplets.empty?
    raise(TypeError, "Entity #{entity} doesn't have any faces. At least one face is required for an entity to be a valid tree collision!", caller)
  end
  tra = entity.transformation
  s = AMS::Geometry.get_matrix_scale(tra)
  flipped = AMS::Geometry.is_matrix_flipped?(tra)
  s.x *= -1 if flipped
  for i in 0...triplets.size
    triplets[i].each { |point|
      point.x *= s.x
      point.y *= s.y
      point.z *= s.z
    }
    triplets[i].reverse! if flipped
  end
  MSPhysics::Newton::Collision.create_static_mesh(world.address, triplets, false, 0)
end

.create_static_mesh2(world, entity) ⇒ Integer

Create a static tree/scene collision.

Parameters:

  • world (World)
  • entity (Sketchup::Group, Sketchup::ComponentInstance)

Returns:

  • (Integer)

    Collision address

Raises:

  • (TypeError)

    if entity has no faces.

Since:

  • 1.0.0



445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'RubyExtension/MSPhysics/collision.rb', line 445

def create_static_mesh2(world, entity)
  MSPhysics::World.validate(world)
  validate_entity(entity)
  tra = entity.transformation
  s = AMS::Geometry.get_matrix_scale(tra)
  flipped = AMS::Geometry.is_matrix_flipped?(tra)
  s.x *= -1 if flipped
  stra = Geom::Transformation.new([s.x,0,0,0, 0,s.y,0,0, 0,0,s.z,0, 0,0,0,1])
  mesh = AMS::Group.get_triangular_mesh(entity, true, stra, &ENTITY_VALIDATION_PROC)
  if mesh.count_polygons == 0
    raise(TypeError, "Entity #{entity} doesn't have any faces. At least one face is required for an entity to be a valid tree collision!", caller)
  end
  triplets = Array.new(mesh.count_polygons)
  for i in 0...mesh.count_polygons
    triplets[i] = mesh.polygon_points_at(i+1)
  end
  c = MSPhysics::Newton::Collision.create_static_mesh(world.address, triplets, false, 0)
end

.validate_entity(entity) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Verify that entity is valid for collision generation.

Parameters:

  • entity (Sketchup::Group, Sketchup::ComponentInstance)

Raises:

  • (TypeError)

    if entity is deleted.

  • (TypeError)

    if entity has a transformation matrix with non-perpendicular axis.

  • (TypeError)

    if entity has at least one of the axis scaled to zero.

Since:

  • 1.0.0



36
37
38
39
40
41
42
43
44
45
46
# File 'RubyExtension/MSPhysics/collision.rb', line 36

def validate_entity(entity)
  AMS.validate_type(entity, Sketchup::Group, Sketchup::ComponentInstance)
  raise(TypeError, "Entity #{entity} is deleted!", caller) unless entity.valid?
  unless AMS::Geometry.is_matrix_uniform?(entity.transformation)
    raise(TypeError, "Entity #{entity} has a non-uniform transformation matrix. Some or all matrix axis are not perpendicular to each other.", caller)
  end
  s = AMS::Geometry.get_matrix_scale(entity.transformation)
  if s.x.to_f < MSPhysics::EPSILON || s.y.to_f  < MSPhysics::EPSILON || s.z.to_f < MSPhysics::EPSILON
    raise(TypeError, "Entity #{entity} has one of the axis scaled to zero. Zero scaled shapes are not acceptable!", caller)
  end
end