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.
You do not need eval here as your code is already being evaluated by Ruby’s interpreter.
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 ?
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.
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 :
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).
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.
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.
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 somethingmust 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
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.