Moving an instance by swapping the transform

Is there a direct method to do that? Or do I have to calculate the transform to get it from where it is to where I want it?

So far I’ve been deleting the instance and recreating it, but that means a new GUID.

Thanks,
Jim

I’m not very familiar with instances, but I think you should be able to do something along the lines of the following:

get the InstanceDefinition from the doc.InstanceDefinitions list

instance = doc.InstanceDefinitions.Find(<GUID>)

get the list of InstanceObjects that the definition has

references = instance.GetReferences()

(each reference object can have a different transform)

set the new transform and commit the changes to the object

references[0].InstanceXform = myNewTransform
references[0].CommitChanges()

(what always confuses me is the difference between the block/instance definition and the actual block/instance objects)

I was hoping I could do something like that but the property is read-only.

Ah, ok.
For “normal” objects, this works:

doc.TransformObject(obj, myNewTrannsform, true)
see http://4.rhino3d.com/5/rhinocommon/html/M_Rhino_DocObjects_Tables_ObjectTable_Transform_1.htm

Hopefully for InstanceObjects it works too, in that it updates the InstanceXform.

Heh, you would think that would work, I’m trying it now (after guessing what I need to do to the transforms to get the “difference” between them) and it’s saying Transform takes 4 arguments not 3…which it doesn’t. EDIT. I did fix that, still just trying to figure out exactly how to multiply the matrices together to get the transform I want…EDIT…which is still kickng my butt.

I’m baffled, if I delete the curve and redraw it, it works fine, if I figure out the rotation between the current position and where I want it to end up (in a brute-force manner of making vectors about the origin and transforming and getting the rotation transform between them) and Transform the instance, there is some sort of error in the transform, the instances go flying off into space, but all my testing so far(again by comparing vectors) to see if the block gets transformed right seems to indicate it does.

Hi Jim

If I understand correctly the problem, rs.XformInverse() can help here.
This test script transforms the source instance into the target instance.
To get the transformation from the source instance to the target instance
it inverts the source instance transform and multiplies it by the target instance transform …
if that makes sense … :smiley:

import rhinoscriptsyntax as rs

def main():
  id0 = rs.GetObject( 'Source instance ?' )
  if not id0:
    return
  xf0 = rs.BlockInstanceXform( id0 )
  id1 = rs.GetObject( 'Target instance ?' )
  if not id1:
    return
  xf1 = rs.BlockInstanceXform( id1 )
  xfi = rs.XformInverse( xf0 )
  xfo = rs.XformMultiply( xf1, xfi )
  id2 = rs.TransformObject( id0, xfo )

main()

Cheers

1 Like

Thanks, I am trying to do basically that, though all in RhinoCommon, but it’s just sending everything into space. I know the transform I’m trying to do is correct, since if I just delete and recreate the instance it’s fine. That said…as a plan B…is it possible(since this is how everything works internally anyway) to delete the instance and make a new one, assigning it the same GUID? There seem to be “replace” methods for most kinds of geometry but not instances…

I tried to write the test in RhinoCommon
Does this work ?

import Rhino

def main():
  result, obref0 = Rhino.Input.RhinoGet.GetOneObject( 
      'Source instance ?', True, Rhino.DocObjects.ObjectType.InstanceReference )
  if result != Rhino.Commands.Result.Success:
    return
  inst0 = obref0.Geometry()
  xf0 = inst0.Xform
  Rhino.RhinoDoc.ActiveDoc.Objects.UnselectAll()
  Rhino.RhinoDoc.ActiveDoc.Views.Redraw()
  result, obref1 = Rhino.Input.RhinoGet.GetOneObject( 
      'Target instance ?', True, Rhino.DocObjects.ObjectType.InstanceReference )
  if result != Rhino.Commands.Result.Success:
    return
  inst1 = obref1.Geometry()
  xf1 = inst1.Xform
  ok, xfi = xf0.TryGetInverse()
  if not ok:
    return
  xfo = xf1 * xfi
  Rhino.RhinoDoc.ActiveDoc.Objects.Transform( obref0, xfo, True )
  Rhino.RhinoDoc.ActiveDoc.Views.Redraw()

main()

And … yes, I looked for a way to replace a block instance too … but found nothing … :frowning:

Cheers

It seems funny there isn’t a specific method…maybe omitting such niceties helps to keep blocks “light.”

I’m not sure which details weren’t quite right in my version but modeling it after your example did finally get it to work, thanks.

…Another somewhat related question…how would I in RhinoCommon do the equivalent of ReplaceBlock?

I’m trying to rewrite this as a rhino script to integrate into a larger script that already exists. But I’m having trouble translating python to rhinoscript. Im using ObjectByLayer as opposed to prompting for the input.

Clearly I’m stumped and missing some fundamental logic. Here is what i have so far. Any ideas/help is appreciated.

Rhino.UnselectAllObjects
			arrTarget = Rhino.ObjectsByLayer("Target", True)
			arrSelected = Rhino.SelectedObjects
		
			If IsArray(arrSelected) Then
				

				arrTargetXform = Rhino.BlockInstanceXform(strObject)

				If IsArray(arrTargetXform) Then

					Rhino.UnselectAllObjects
					arrSource = Rhino.ObjectsByLayer("Source", True)
					arrSelected = Rhino.SelectedObjects
					
					arrSourceXform = Rhino.BlockInstanceXform(strObject)
					
					Rhino.TransformObject strObject, Rhino.XformInverse(arrTargetXform)

				End If
				
			
				
					
			End If

Another attempt.

It keep getting an error “Type mismatch in parameter. String required” when I use the Rhino.BlockInstanceXform(strObject)

                Rhino.UnselectAllObjects
				arrSource = Rhino.ObjectsByLayer("Source", True)
				arrSourcexform = Rhino.BlockInstanceXform(strObject)
				
				Rhino.UnselectAllObjects
				arrTarget = Rhino.ObjectsByLayer("Target", True)
				arrTargetxform = Rhino.BlockInstanceXform(strObject)
				
				
				arrResult = Rhino.XformInverse(arrSourceXform)
				
				arrMover = arrTargetxform * arrResult
				
				Rhino.TransformObject arrSource, arrMover, True

Where is strObject defined ?
I cannot see where it comes from … :slight_smile:

I see what you’re your saying. I’m not a developer, so I make rookie mistakes :confused: Here is another attempt. Now it throws a “type mismatch” error indicated in the script below. I appreciate the help!

                arrObjects = Rhino.ObjectsByType(4 + 8 + 16 + 32 + 4096, True)
				If Not IsArray(arrObjects) Then Exit Sub
				
				For Each strObject In arrObjects
		
					If IsArray(arrObjects) Then	
				
						If Rhino.IsBlockInstance(strObject) Then
							
							Rhino.UnselectAllObjects
							arrSource = Rhino.ObjectsByLayer("Source", True)
							arrXform = Rhino.BlockInstanceXform(strObject)
							
							Rhino.UnselectAllObjects
							arrTarget = Rhino.ObjectsByLayer("Target", True)
							arrTargetXform = Rhino.BlockInstanceXform(strObject)
							
							
    							arrResult = Rhino.XformInverse(arrXform)
    							
                 `'This is the line that errors.`  
    							arrMove = arrXform * arrResult
    							
    							Rhino.TransformObject arrSource, arrMove, True
    						
    						End If
						
					End If
				
					
				Next

I think you can’t multiply two transforms with ‘*’ in Rhinoscript (you can in Python).

Maybe try arrMove=Rhino.XformMultiply (arrXform, arrResult)

But why are you multiplying a transform with its inverse?

lol, I don’t know. I was trying to deconstruct the python script in the thread above.

I’m trying to replace the Target with the Source while using the transform, scale, rotation properties of the Target. Swap blocks.

rhino.command replaceblock works great but I can’t figure out how to bypass the manual inputs via a script.

I found the python example above. Got it to work for my needs, but now i need to embed it into a much larger script that is already written in rhino.script. So I was attempting to deconstruct the python example and translate it into rhino script.

ok, now it runs the script successfully without errors, but the result appears to place all the blocks that are stored in the block manager at 0,0,0. the blocks have not been scaled.

            arrObjects = Rhino.ObjectsByType(4 + 8 + 16 + 32 + 4096, True)
			If Not IsArray(arrObjects) Then Exit Sub
			
			For Each strObject In arrObjects
	
				If IsArray(arrObjects) Then	
			
					If Rhino.IsBlockInstance(strObject) Then
						
						'	Rhino.Command "-Purge "
						
						'Center
						Rhino.UnselectAllObjects
						arrSource = Rhino.ObjectsByLayer("Source", True)
						arrSelected = Rhino.SelectedObjects
						If IsArray(arrSelected) Then
							arrXform = Rhino.BlockInstanceXform(strObject)
						End If
						
						
						Rhino.UnselectAllObjects
						arrTarget = Rhino.ObjectsByLayer("Target", True)
						arrSelected = Rhino.SelectedObjects
						If IsArray(arrSelected) Then
							arrTargetXform = Rhino.BlockInstanceXform(strObject)
						End If
						
						
						Rhino.TransformObject strObject, Rhino.XformInverse(arrTargetXform), True
						
					
					End If
					
				
					
				End If
			
				
			Next

I tried to translate the first script I posted into VBS.
Here it is.
It seems to work here …

sub main
id0 = rhino.GetObject( "Source instance ?" )
if isnull( id0 ) then exit sub
xf0 = rhino.BlockInstanceXform( id0 )
id1 = rhino.GetObject( "Target instance ?" )
if isnull( id1 ) then exit sub
xf1 = rhino.BlockInstanceXform( id1 )
xfi = rhino.XformInverse( xf0 )
xfo = rhino.XformMultiply( xf1, xfi )
id2 = rhino.TransformObject( id0, xfo )
end sub

main

HTH

Thanks so much for your help. I really appreciate the time you’ve taken to help me.

I remain confused as to why I’m having so much trouble converting this to work within another script. If I use it as-is, it works perfectly! As soon as I try to automate the selection for the Source and Target I get errors like str required. This was the first approach that gives the error ‘Type mismatch in parameter. String required.’

If I change the selection method (first two lines) I get the error

               'id0 = rhino.GetObject("Source instance ?")    CHANGE TO
				id0 = Rhino.ObjectsByLayer("Source", True)   
				If isnull(id0) Then Exit Sub
				xf0 = rhino.BlockInstanceXform(id0)
				id1 = rhino.GetObject("Target instance ?")
				If isnull(id1) Then Exit Sub
				xf1 = rhino.BlockInstanceXform(id1)
				xfi = rhino.XformInverse(xf0)
				xfo = rhino.XformMultiply(xf1, xfi)
				id2 = rhino.TransformObject(id0, xfo)

So I attempted to move some things around and change the code structure to match the larger scripts structure. The selection portion appears to work now, but when I try to do the Xform Multiply I get an error that says ‘Type mismatch in parameter. Array required.’

I’m stumped and in over my head.

			    Rhino.UnselectAllObjects
				arrSource = Rhino.ObjectsByLayer("Source", True)
				arrSXform = Rhino.BlockInstanceXform
				arrSXformInv = Rhino.XformInverse		
							
                Rhino.UnselectAllObjects
				arrTarget = Rhino.ObjectsByLayer("Target", True)	
				arrTXform = Rhino.BlockInstanceXform
					
				'This is where the error occurs
				arrDiff = Rhino.XformMultiply(arrTXform, arrSXformInv)				

				arrMove = rhino.TransformObject(arrSource, arrMath)