Insert Block in different CPlanes

Which part of blocks did I not understand?

  1. I define a block “top” in the top view (CPlane set to top):
  2. I insert the block in the front view and it works as expected: the block is oriented in the front-CPlane
  3. I insert the block in the right view and it works as expected: the block is oriented in the right-CPlane

Now:

  1. I define a block “front” in the front view (Cplane set to front):
  2. I insert the block in the front view - it’s oriented in the top-Cplane:
  3. I insert the block in the right view - it’s oriented in the top-Cplane but rotated
  4. I insert the block in the top view - it’s oriented in the front-Cplane:

So, Rhino defines a block always in the World-Cplane but then inserts it in the current CPlane.

Am I the only one who finds this counter-intuitive? Or just the only one who wants to define a block somewhere in space and than insert it flat on the XY-Plane?

Yep, that is indeed how it works. This way you can insert say your screw in the correct orientation. But always assume World when the block is defined.

-Pascal

Wow @pascal, that was a quick reply! Thanks.

Your screw-example would still work fine when the CPlane was regarded during definition, wouldn’t it? You would just need to make sure that CPlane=World to get the current behavior.

But what doesn’t work now is to “pick up” the screw in its original oriention somewhere in space and still create a screw-block where the screw is aligned with, say, the x-axis. I cannot just set the CPlane’s x-axis to match the screw and define the block. First I have to Orient3D the screw to the world x-axis, then define the block there and then insert it in the original location.

Haven’t worked with ACAD in a while, but I think I remember it works there - which actually provides more flexibility without any real drawbacks?

Well, imagine a screw being as a file, though - that has to work consistently - so a plane other than the World is not part of the block… but if your goal is to make a World oriented block from the current CPlane, this may help, for now:

BlockWorld.py (983 Bytes)

To use the Python script use RunPythonScript, or a macro:

_-RunPythonScript "Full path to py file inside double-quotes"

Does that do what you need?

-Pascal

Thanks for the Python example! That saves me some time :slight_smile:

I understand that there is no plane other than WorldXY stored in a block, but this isn’t actually necessary!

Since you mention it: I just found out that _ExportWithOrigin actually works exactly the way I described above. It takes the active CPlane as the new WorldXY-Plane for the exported file. When I then re-insert the file as block-instance in the same CPlane, I get exactly what I expect: it’s oriented the same as before.

Now the question: why can’t _Block do just the same? “Implicitly” re-orient the objects from CPlane to WorldXY, define the block as it does now and re-insert it in the CPlane. When this is done from WorldXY, the result is precisely the same as it is now. From any other CPlane it adds functionality and comfort.

And consistency: Now, when I create a block in a view with a CPlane, I get a block instance exactly where my objects have been. When I then - without changing the CPlane! - try to insert this same block a second time, the orientation is different!! WTF?! I have to find our discussion here to understand it… :wink:

Fabian

Hi Fabian - I do not see why Block could not be made, optionally, to orient to the world based on the current CPlane, much like the script.

https://mcneel.myjetbrains.com/youtrack/issue/RH-55914
-Pascal

1 Like

Looking forward to that!
Luckily I can code it until then :smiley:

Merci
Fabian

Wow this scripts is really close to what I need! Hope you don’t mind if I build upon your code to make it so one can specific an origin point rather than always uinsg Wxy.Origin.

One question: I’m having a hard time understand this line:
bId = sc.doc.Objects.AddInstanceObject(idx, xform2.TryGetInverse()[1] )
why is there a [1] at the end, why is it important here to extract part of the transformation matrix?

In the end I made it work like this, but not really sure why it worked:
def DefineWorldBasedBlock():

ids = rs.GetObjects("Select objects to block.", preselect=True)
if not ids: return

bPlane = rs.ViewCPlane()
if bPlane is None: return

Wxy = Rhino.Geometry.Plane.WorldXY
Wxy_n = Rhino.Geometry.Plane.WorldXY
xform1 = Rhino.Geometry.Transform.PlaneToPlane(bPlane, Wxy)

point = rs.GetPoint("Select Block Origin Point")
if( point == None):
    point = Wxy.Origin
else:
    bPlane.Origin = point
    Wxy_n.Origin = point
    xform2 = Rhino.Geometry.Transform.PlaneToPlane(bPlane, Wxy_n)
    xform3 = Rhino.Geometry.Transform.PlaneToPlane(bPlane, Wxy)

name= rs.StringBox("Block name", title="World Block")
if not name: return
objs = [sc.doc.Objects.Find(id) for id in ids]

geos = [obj.Geometry for obj in objs]
attrs = [obj.Attributes for obj in objs]

for geo in geos:
    geo.Transform(xform2)
sc.doc.InstanceDefinitions.Add(name, "", point, geos, attrs)
print "Block " + name + " defined."

idx = sc.doc.InstanceDefinitions.Find(name).Index
bId = sc.doc.Objects.AddInstanceObject(idx, xform3.TryGetInverse()[1] )
rs.DeleteObjects(ids)

Thank you!

I’m also trying to solve for the case where the name of the block already existed and enable the script to overwrite the old block definition.

In the Rhino common I did not find out a method to overwrite an existing instance definition, delete definition does not work because it will delete all reference too. ModifyGeometry is very close, but after testing I did not find out how this method actually determines the orientation of the geometry being modified in relation to the origin point of the old definition, which makes it kind of useless.

The method Transform.TryGetInverse() returns a tuple (boolean, xform) with a success flag and the resulting matrix (if any). Actually you should check the boolean first before using the result, or you might run into an exception if the method failed. But here the inversion should be rather straightforward, therefore the second item in the returned tuple is accessed directly by its index.

see https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Transform_TryGetInverse.htm

1 Like

Ah that makes sense, thank you

Current behaviour (block plane definition) is not very universal since its locked to world. I have come to its bottleneck today:

i modelled geometry in some place and made a block
…created many instances in different orientations…
i modified the block (explode and define new block)
i replaced selected instances
their orientations were totally off (of those replaced ones)

i guess i modified and defined the block not in the same plane when i made a modified version.
Subsequent replacement was therefore very off.

I think only solution for this is to define plane instead of an insertion plane when defining a block.