Sketchup Crashing with unstability generated

Hi there,

I’m lookingsome explanation to a strange thing…

The code I’m writing does things whithout problems and I’m reaching a new method that practice boolean operations on elements that I need to merge at there actual places. But they are spread into différent groups meaning their transformations inheritance are differents and Group cretion with instances does ot match because of beloning to different hierarchy parents (ie : local transformation herit from different perents transformation. Usual to 3D, local / world matrix).

Before the method call Sketchup status is clean but after the method call Sketchup is unstable and crash at different positions when lauching th debug.

My question is : what do I call that inject unstable to Sketchup Status ?

Here is the method content :

def mergeCVitems
    angleItemsCorner = (@data["ANGLE"]["POS"] == "L") ? 1 : 0
    doorItemsCorner = (@data["ANGLE"]["POS"] == "L") ? 0 : 1


    #CLEAN AND COMBINE ITEMS
    upDownItems = ["CV|VH", "CV|VV", "CV|SHH", "CV|SHV"]
    upDownItems << "CHA" if @cornerObjects[1]["DATA"]["CS?"]

    upDownItems.each do |currentItemTag|
      #Get the CV items
      currentElements = (0..1).collect do |ind|
        #Extract persistent ID
        currentItemPID = eval(@cornerObjects[ind]["ENT"].get_attribute(@entityAD_name, currentItemTag, ""))

        #Get the entity
        currentElem = Sketchup.active_model.find_entity_by_persistent_id(currentItemPID)[-1]
        currentElem
      end

      #Instaciate them into the CV container and delete the previous ones
      cvContainer = @object.entities.add_group()
      toDelete = [@object.entities.add_cpoint([0,0,0])]
      cvContainer.name = "CV Unify"

      elementToMerge = (0..1).collect do |currentInd|
        #Import the CV element
        currentElem = currentElements[currentInd]
        importGrp = cvContainer.entities.add_group(currentElem)

        #Cleanup and retrieved imported instance
        importGrp.explode.grep(Sketchup::ComponentInstance)[0]
      end

      #Merge the CV connected components
      ##Bkp Definition data and merge them
      mergeDefinitionName = elementToMerge[0].definition.name
      mergeDefinitionMat = elementToMerge[0].material

      ##Merge elements
      mergeElement = elementToMerge[0].union(elementToMerge[-1])
      mergeElement = mergeElement.to_component
      mergeElement.definition.name = mergeDefinitionName
      mergeElement.material = mergeDefinitionMat
    end
  end

Do not esitate to ask questions to clarify things.

Thanks all for your helps and explanations !

Please post code correctly on the forum …


Some items, I don’t know if it is your problem:

  1. You do not need eval here as your code is already being evaluated by Ruby’s interpreter.

  2. You are not using defensive coding practices. What if currentItemPID is “”` ? … If it is empty, should you be trying to find the object by persistent_id ?

  3. What is @entityAD_name ? Please remember that the model scope is a shared scope, so all attribute dictionary names should be unique and it is probably best to use the unique name of your extension.


When you post a complex issue this this, in order to understand, it is best to provide a same sample model to test with. Also, there are a number if instance variables in use that we do not know what they are.

Your introduction does not actually state what it is that the code is attempting to accomplish.

Hi Dan,

Thanks for your quick answer, I know that my post is short but if wanted to have an idea of what could impact stability and not diging people into the code. If you prefer it I can give you as private message the Github path to the project.

To clarify it, I was creating a Plugin for a house wood construction starting with frame modeling (single tool generation, csv frame generation, angle frame generation in which the code is extracted). The other coder I’m working with, is a new coder and working on dynamic components and quote building.

Rgarding your first questions :

  1. I’m doing eval into ruby code because I’m storing persistent_id of key elements into the frame group qttribute dictionnary as string that I need to eval when retriving them to get the related object. This allow to use the Plugin to do things days ater the first pass (which is the use of the persistent_id).
  2. currentItemPID is the variable that hold the DrawingElement of the persistent ID to be manipulated later on, extracting it (as I said previously) from attribute dictionnary of the Drawing Element Entity.
  3. As I said, the code was to big and I didn’t wanted to explain it all and force you to dig into it (tell me if you want the GitHub Link). For other info the code was ok before I started the section I posted here. Again, I was asking if there was something that impacts stability into it.

I hope that quick answer allow a bit of explantations. I’m waiting for your answer if you need the Github project link and idears hof what to gives you to extract clues. :wink:

After making some research. The part of the code that make problem is this one :

      elementToMerge = (0..1).collect do |currentInd|
        #Import the CV element
        currentElem = currentElements[currentInd]
        importGrp = cvContainer.entities.add_group(currentElem)

        #Cleanup and retrieved imported instance
        importGrp.explode.grep(Sketchup::ComponentInstance)[0]
      end

I’m trying to generate a temp importGrp group into cvContainer group that allow me to make a copy a the same place of the existing frame object which is a ComponentInstance (heriting from DrawingElement which have Transformation).

The other way (which is the best way to me), should be to create a new ComponentInstance from ComponentDefinition at the wrigt place. But the problrm is to me that I don’t understand how to manipulate objects in the world coordinates because all is using Local Transformetion to the container (ie : ComponentDefinition which ComponentInstance hold the transformation or Group).

Can you explain me how to apply world transformation (ie: position mainly). I know the is the InstancePath that give the object hierarchy and I can get all the local transformations to generate the world transformation of the object * by the destination reverse world transformation to get the local transformation to be applied when adding a new instance in its container (ie Group or ComponentDefinition).

Can you give me direction how to do it ?

In advance, thanks a lot !

For info I have prepared futur extension code to basic Entity class :

#EXTEND Sketchup::Entity CLASS
class Sketchup::Entity
  @@realContainers = [Sketchup::Group, Sketchup::ComponentInstance]
  def self.realConatinersKlass; @@realContainers; end

  @@useContainers = [Sketchup::Model, Sketchup::Group, Sketchup::ComponentDefinition]
  def self.useConatinersKlass; @@realContainers; end

  @@AttrDictName = "MATRIX"
  def self.attrDictName; @@AttrDictName; end

  @@AttrPidPathName = "PID_PATH"
  def self.attrPidPathName; @@AttrPidPathName; end

  def explode!
    containerKlasses = [Sketchup::Group, Sketchup::ComponentInstance]
    return false if containerKlasses.include? self.class

    #Explode subEntities
    selfEntities = (self.class == Sketchup::ComponentInstance) ? self.definition.entities.to_a : self.entities.to_a
    selfEntities.each do |subEntity|
      #Explode recursively the sub entities which are containers
      if containerKlasses.include? subEntity.class
        subEntity.explode! unless containerKlasses.include? subEntity.class
      end
    end

    self.explode
  end

  def getHierarchyParent
    #FIND CONTAINER
    parentDefinition = self.parent
    hierarchyParent = nil

    #Set the single instance as parent
    if parentDefinition.class != Sketchup::Model
      if parentDefinition.instances.length == 1
        hierarchyParent = parentDefinition.instances[0]

      #Either identify the parent using the inspect string as ID
      else
        stringID = self.inspect
        parentDefinition.instances.each do |current_entity|
          if current_entity.inspect == stringID
            hierarchyParent = current_entity
            break
          end
        end
      end
    end

    return hierarchyParent
  end

  def getPath()
    #Initialize path building
    entityPath = []
    currentEntity = self

    #Parsed hierarchy parent and build entity path
    begin
      entityPath << currentEntity
      currentEntity = currentEntity.getHierarchyParent
    end while !currentEntity.nil?

    #Convert to instancePath
    entityPath = Sketchup::InstancePath.new(entityPath.reverse)

    return entityPath
  end

  def getWorldTransormation
    return getPath.transformation
  end

  def getWorldPosition(argLocalPosition=[0,0,0], argFromMM:false, argToMM:false)
    raise "argLocalPosition is not a valid Array[3]" unless argLocalPosition.class == Array and argLocalPosition.length == 3
    raise "argFromMM is not a valid Boolean" unless [true, false].include? argFromMM
    raise "argToMM is not a valid Boolean" unless [true, false].include? argToMM

    #Prepare the positions
    localOriginPosition = self.getWorldTransormation.to_a[12..14]
    if argFromMM
      argLocalPosition = argLocalPosition.mm if argFromMM
      localOriginPosition = localOriginPosition.to_mm
    end

    #Get entity world transformation position by world transformation
    worldPosition = localOriginPosition.dynOP(argLocalPosition, "+")

    #Convert values to mm
    worldPosition = worldPosition.to_mm if argToMM

    return worldPosition
  end
end

No thank you. I do not desire to debug your whole project.

It is a common pitfall, causing crashes, if the argument objects (currentElem in your case) passed to #add_group are not members of the entities where the new group is added.
Ie:

this_ents.add_group(something)

The new group will be added into this_ents, but something must also be a member of the this_ents entities collection. If something is a member of some other entities collection, then CRASH.

Perfect Dan, your explaination is matching what I’ve noticed but that good to have a real answer that confirm it.

Back to my last question, if I want make boolean operation like union do you confirm that I need to put them in a same container to add instances instances in a same container (Sketchup::Group)?I’ve noticed that the boolean operation does nothing (return nil) in case the argument given to the boolean opertion is not in the same container as the one on which the method is called ?

If you confirm it, can you tell me how to insert, both objects to merge/combine, in the same container keeping the their position/rotate/scale ? Meaning evaluate World Transformations of

  • Container.
  • Object 1 to merge.
  • Object 2 to merge.

This will allow to evaluate Local Transformations to insert a new version of instances in the container with the same position/orientation/scale. Withdraw the container World Inverse Transformation) from Objects World Transformations.

I’m not used to evaluate world transfo : is there a good way to do it ? Which one sould be applied first ? Meaning the Order :

  1. Scale
  2. Rotate
  3. Translate

Thanks for your help :roll_eyes:

Of course, they both must be in the same geometric context, otherwise there can be no Boolean operation.

I have no idea how your model is organized and I really do not have time now to do this.

Both of the objects to be combined should start in the same context and the result will be in that same context. So, they will be in their parent’s coordinate system.

Look into building an InstancePath for the parent and the result. You can get the transformation from the instance paths you build.

You also can leverage: