# Since SU2017 exploding a group replaces all entities

**URL:** <https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102>\
**Category:** Ruby API\
**Created:** [December 20, 2016, 9:31am UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102 "2016-12-20T09:31:53Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bliss](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/bliss/32/19486_2.png) [@Bliss](https://forums.sketchup.com/u/Bliss)\
**Post date:** [December 20, 2016, 9:31am UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/1 "2016-12-20T09:31:53Z")

</div>

To calculate the volume of a solid I used to group the faces of the solid together temporarily, store the volume and explode it immediate after that. In SU2016 the faces don’t change, in SU2017 all my faces are replaced by new faces. Since I store the references of those faces, they now point to deleted entities. Both `entityId` and `persistent_id` are new too.

To see the difference, create a cube and run the following in the console:

```ruby
      before = Sketchup.active_model.entities.grep(Sketchup::Face)
      puts before
      group = Sketchup.active_model.entities.add_group(before)
      volume = group.volume / (1.m * 1.m * 1.m)
      group.explode
      after = Sketchup.active_model.entities.grep(Sketchup::Face)
      puts after
      puts before == after

```

Is this the intended behaviour? Is there another way compatible with both versions?

---

<div class="post-metadata">

**Author:** ![jimhami42](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/jimhami42/32/1781_2.png) [@jimhami42](https://forums.sketchup.com/u/jimhami42)\
**Post date:** [December 20, 2016, 12:55pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/2 "2016-12-20T12:55:00Z")

</div>

Interesting behavior … this returns ‘false’ in 8, 2015, and 2017, but returns ‘true’ in 2016.

---

<div class="post-metadata">

**Author:** ![jim\_foltz](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/jim_foltz/32/74787_2.png) [@jim\_foltz](https://forums.sketchup.com/u/jim_foltz)\
**Post date:** [December 20, 2016, 1:08pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/3 "2016-12-20T13:08:35Z")

</div>

This is the intended behavior starting with version 2017. It is because all entities have a persistent ID in version 2017.

---

<div class="post-metadata">

**Author:** ![john\_drivenupthewall](https://avatars.discourse-cdn.com/v4/letter/j/c67d28/32.png) [@john\_drivenupthewall](https://forums.sketchup.com/u/john_drivenupthewall)\
**Post date:** [December 20, 2016, 1:08pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/4 "2016-12-20T13:08:55Z")

</div>

> [@Bliss](#):
>
> Both entityId and persistent\_id are new too.

`entityId` has been around since v6, `persistent_id` is the new one…

in some that I’ve ‘fixed’ I realised the temp group wasn’t even needed and I could use the existing group entities…

in others, moving the explode to the end of tools code worked…

in one of mine I ‘now’ store the `face.bounds.center.z` and then after exploding re-find the face using that as a conditional…

john

---

<div class="post-metadata">

**Author:** ![Bliss](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/bliss/32/19486_2.png) [@Bliss](https://forums.sketchup.com/u/Bliss)\
**Post date:** [December 20, 2016, 1:38pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/5 "2016-12-20T13:38:12Z")

</div>

> [@john\_drivenupthewall](#):
>
> entityId has been around since v6, persistent\_id is the new one…

Sure, I was trying to say that both change.

> [@jim\_foltz](#):
>
> This is the intended behavior starting with version 2017. It is because all entities have a persistent ID in version 2017.

Okay, so how do I get the volume of this solid without creating a temporary group that destroys my faces? Sure, I probably can “find” the faces again, but this feels quite dirty to me.

---

<div class="post-metadata">

**Author:** ![slbaumgartner](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/slbaumgartner/32/7302_2.png) [@slbaumgartner](https://forums.sketchup.com/u/slbaumgartner)\
**Post date:** [December 20, 2016, 1:39pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/6 "2016-12-20T13:39:10Z")

</div>

> [@jim\_foltz](#):
>
> This is the intended behavior starting with version 2017. It is because all entities have a persistent ID in version 2017.

My brain is slow today. Could you please explain why persistent ID’s make it necessary to delete and recreate entities when you explode a group? I’m struggling with the following thought analogy: I have a box of marbles. If I dump them out of the box, aren’t they still the same marbles?

---

<div class="post-metadata">

**Author:** ![jim\_foltz](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/jim_foltz/32/74787_2.png) [@jim\_foltz](https://forums.sketchup.com/u/jim_foltz)\
**Post date:** [December 20, 2016, 1:46pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/7 "2016-12-20T13:46:33Z")

</div>

SketchUp doesn’t dump them out, it crushes the marbles in a hydraulic press then makes new marbles.

I have no idea if it’s necessary or not. It’s just how SketchUp now works.

I thought I remember the reason given was persistent ID’s but I could be mistaken.

---

<div class="post-metadata">

**Author:** ![john\_drivenupthewall](https://avatars.discourse-cdn.com/v4/letter/j/c67d28/32.png) [@john\_drivenupthewall](https://forums.sketchup.com/u/john_drivenupthewall)\
**Post date:** [December 20, 2016, 2:01pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/8 "2016-12-20T14:01:41Z")

</div>

persistent\_id’s will work in the given example, if you compare them sorted…

```ruby
before = Sketchup.active_model.entities.grep(Sketchup::Face)
pids1 = []
before.each{|f| pids1 << f.persistent_id }

group = Sketchup.active_model.entities.add_group(before)
volume = group.volume / (1.m * 1.m * 1.m)
group.explode
after = Sketchup.active_model.entities.grep(Sketchup::Face)
pids2 = []
after.each do |f| 
  pids2 << f.persistent_id
  Sketchup.active_model.selection.add([f, f.edges]) if pids1.include? f.persistent_id
end  
     
pids1.sort == pids2.sort      

```

> [@Bliss](#):
>
> how do I get the volume of this solid without creating a temporary group

if it’s a ‘solid’ it’s already a group, why do you need the temp group?

john

---

<div class="post-metadata">

**Author:** ![tt\_su](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/tt_su/32/17_2.png) [@tt\_su](https://forums.sketchup.com/u/tt_su)\
**Post date:** [December 21, 2016, 1:14pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/9 "2016-12-21T13:14:26Z")

</div>

The preservation of entityId when exploding in previous versions was an implementation detail. The API never guarantied this. When we implemented persistent ID’s this implementation detail changed for various reasons in order to ensure consistent persistent IDs. The regular entityIDs has always been a very transient property.

---

<div class="post-metadata">

**Author:** ![adrigon](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/adrigon/32/38458_2.png) [@adrigon](https://forums.sketchup.com/u/adrigon)\
**Post date:** [December 30, 2017, 2:14pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/10 "2017-12-30T14:14:37Z")

</div>

Hi everybody, I have the same issue as Bliss.

I try to reformulate it my way :

I want to compute the volume of a manifold **not stored in a group**. To do so, I create a **temporary** group, compute the volume, store the result in a variable and then explode it. My geometry hasn’t changed and it’s okay, nervertheless **all the entities (faces, …) change their reference** so all my variable that previously pointed to them now point to some “Deleted Entity” and I get an error if I work on them : \<TypeError: reference to deleted Face\> .

My questions are :

- can create a groupe with the copy of my entities to compute the volume and thus not deleting the original entities ?
- is there an other way to compute the volume without grouping ?

Thank you in advance for your precious help.

Adri

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [December 30, 2017, 4:54pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/11 "2017-12-30T16:54:24Z")

</div>

**INJECT:** _posted below:_[**No temporary group method (based on old AdamB post)** …](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/13)

* * *

This seems to work, tested on SU2016:

```ruby
# get_volume(geometry)
# Create a temporary group, get the volume and undo.
#
# @param geometry [Array<Drawingelement>] Array of collected geometry references.
# @return [Float] the computed volume if successful, 0.0 if not.
def get_volume(geometry)
  volume = 0.0
  model = Sketchup::active_model
  model.start_operation('Temp Group',true)
    #
    ents = model.active_entities
    grp = ents.add_group(geometry)
    volume = grp.volume
    #
  model.commit_operation
rescue => e
  puts e.inspect
else
  Sketchup::undo
ensure
  puts "get_volume() returned: #{volume} in³"
  return volume
end

```

However, if some other extension creates a undo operation and attaches it to this one (from behind or next) their’s will also be undone. (IMO, that is their fault.)

* * *

**EDIT:** The example _assumes_ that the geometry objects are in the current **active entities** collection.  
If they are not, then you’ll need to modify the code to get the parent entities collection of the geometry:

```ruby
# perhaps just before the undo operation ...
sire = geometry.first.parent
ents = sire.entities
return 0.0 unless geometry.all? {|e| e.parent == sire }

```

… and remove the line inside the operation that assigns **`ents`**.

---

<div class="post-metadata">

**Author:** ![TIG](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/tig/32/198_2.png) [@TIG](https://forums.sketchup.com/u/TIG)\
**Post date:** [December 30, 2017, 5:17pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/12 "2017-12-30T17:17:41Z")

</div>

Let’s us assume the geometry in question is temporarily placed inside a ‘`group`’  
The explode returns an array of objects.

```ruby
ex = group.explode

```

This includes all resulting edges and faces, and more besides - like curves…  
You can filter it - see below

So to make your code suitable for all supported versions you could consider adding a ‘marker’ attribute to say the faces [or edges if desired].  
This will be passed to the replacement entities after the explode, so before grouping we ‘mark’ the faces…

```ruby
faces.each_with_index{|face, i| face.set_attribute('adrigon', 'marker', i) }

```

After exploding retrieve the replacement faces:

```ruby
hashed_faces = {}
ex.grep(Sketchup::Face).each{|face|
  next unless i = face.get_attribute('adrigon', 'marker', nil)
  hashed_faces[i] = face
}
sorted_ex_faces = []
hashed_faces.keys.sort.each{|k|
  sorted_ex_faces << hashed_faces[k]
}

```

You now have an array of those newly exploded faces, ordered as they were in the original geometry [and ‘`faces`’ array]…

If desirable you can also finally reset your ‘marker’ attribute associated with these replacement faces to ‘`nil`’…

* * *
This will work across all SketchUp versions. BUT if you only want \>= v2017 compatibility, then just use the newer persistent ids and trap for `Sketchup.version` to suit.......

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [December 30, 2017, 6:41pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/13 "2017-12-30T18:41:25Z")

</div>

@adrigon, @TIG pointed me toward an [old thread on SketchUcation](http://sketchucation.com/forums/viewtopic.php?f=323&t=1532) in which …  
@AdamB [proposed a totally mathematical solution, [u]without a temporary group[/u]](http://sketchucation.com/forums/viewtopic.php?p=14598#p14598).

Following is my rendition of this solution.

Mine does **not** modify API class [`Geom::Point3d`](http://ruby.sketchup.com/Geom/Point3d.html), but converts to an [`Array`](http://ruby.sketchup.com/Array.html) which already has a [`#dot`](http://ruby.sketchup.com/Array.html#dot-instance_method) method.  
Mine also uses [`#grep`](http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-grep) which is very fast when comparing class identity, … instead of calling [`#is_a?`](http://ruby-doc.org/core-2.0.0/Object.html#method-i-is_a-3F) on each and every object in the `geometry` collection on the Ruby-side, during each iteration.

```ruby
# calculate_volume(geometry)
# Calculate volume on a set of faces without a temporary group.
#
# Based on an old SCF topic thread post by AdamB:
# http://sketchucation.com/forums/viewtopic.php?p=14598#p14598
#
# @param geometry [Array<Drawingelement>] Array of collected geometry references.
# @return [Float] the computed volume (in inches) if successful, 0.0 if not.
def calculate_volume(geometry)
  geometry.grep(Sketchup::Face).map {|f|
    (2 * f.area * (f.vertices[0].position.to_a.dot(f.normal))) / 6      
  }.reduce(:+)
rescue => e
  puts e.inspect
  return 0.0
end

```

* * *

_Snipped off volume format string to new topic:_

- [[Code] format volume in model units](https://forums.sketchup.com/t/code-format-volume-in-model-units/58562/1)

---

<div class="post-metadata">

**Author:** ![adrigon](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/adrigon/32/38458_2.png) [@adrigon](https://forums.sketchup.com/u/adrigon)\
**Post date:** [December 30, 2017, 8:50pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/14 "2017-12-30T20:50:28Z")

</div>

Thank you so much Dan.  
It looks perfect. I just need to give it a little try.

---

<div class="post-metadata">

**Author:** ![rvs1977](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/rvs1977/32/15210_2.png) [@rvs1977](https://forums.sketchup.com/u/rvs1977)\
**Post date:** [December 30, 2017, 8:53pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/15 "2017-12-30T20:53:28Z")

</div>

A work around could be to make a temporarily copy of the group which you can delete when done…

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [December 30, 2017, 9:04pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/16 "2017-12-30T21:04:07Z")

</div>

> [@rvs1977](#):
>
> A work around could be to make a temporarily copy of the group which you can delete when done…

**Except** , … that there is **no** group. It is raw geometry. (Please read the thread.)

---

<div class="post-metadata">

**Author:** ![john\_drivenupthewall](https://avatars.discourse-cdn.com/v4/letter/j/c67d28/32.png) [@john\_drivenupthewall](https://forums.sketchup.com/u/john_drivenupthewall)\
**Post date:** [December 30, 2017, 9:39pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/17 "2017-12-30T21:39:03Z")

</div>

@DanRathbun, on a 1.0m³ your code is returning 1550.0m³…

john

---

<div class="post-metadata">

**Author:** ![slbaumgartner](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/slbaumgartner/32/7302_2.png) [@slbaumgartner](https://forums.sketchup.com/u/slbaumgartner)\
**Post date:** [December 30, 2017, 10:04pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/18 "2017-12-30T22:04:28Z")

</div>

That’s because 1m^3 = 61023.744in^3. If you treat that as inches and apply format\_length, it works out to 1550.0m. The format\_volume\_in\_model\_units method given is wrong!

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [December 30, 2017, 10:31pm UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/19 "2017-12-30T22:31:28Z")

</div>

> **complaints ...**
>
> > [@john\_drivenupthewall](#):
> >
> > on a 1.0m³ your code is returning 1550.0m³…
> 
> > [@slbaumgartner](#):
> >
> > The format\_volume\_in\_model\_units method given is wrong!

_Removed from previous posts and began new topic on volume format string :_

- [[Code] format volume in model units](https://forums.sketchup.com/t/code-format-volume-in-model-units/58562/1)

---

<div class="post-metadata">

**Author:** ![rvs1977](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/rvs1977/32/15210_2.png) [@rvs1977](https://forums.sketchup.com/u/rvs1977)\
**Post date:** [December 31, 2017, 9:08am UTC](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102/20 "2017-12-31T09:08:07Z")

</div>

you are right…and surly it isn’t a beautiful advice… copy the raw geometry to a temporarily group - measure the volume - then delete the temporarily group again.

[Next page](https://forums.sketchup.com/t/since-su2017-exploding-a-group-replaces-all-entities/36102.md?page=2)
