ObjectData::GetDimension() ignored?

Hi guys.
ObjectData::GetDimension() callback is ignored in most of the cases.

  1. When ObjectData::GetVirtualObjects() callback returns null object, in this case GetDimension() is completely ignored. It is the case when it would be most useful!

  2. When ObjectData::GetVirtualObjects() callback returns valid PolygonObject, in this case GetDimension() is again ignored because the plugin is calculating dimension from returned PolygonObject.

Is there some additional settings which needs to be set to force plugin to use GetDimension()?

Thanks!

Hello @wtools3d,

Thank you for reaching out to us. Unfortunately, your question is a bit ambiguous, especially regarding how you register your plugin and what you would consider to be "to be completely ignored", and finally the code you have written.

Our C++ ObjectData example plugin Rounded Tube does overwrite ::GetDimension and it does what I would expect it to do.

  1. ObjectData::GetDimension is called when BaseObject::GetDimension is invoked (or its Python counter parts .GetMp() and .GetRad()). The call chain from BaseObject::GetDimension goes through our core and visits during this also ObjectData::GetDimension. There are of course fallback methods in place which take over when ObjectData::GetDimension is not implemented, but I neither see any general conditions which would suppress the output from ObjectData::GetDimension nor is there a difference when I inspect the values.
  2. The only central exit conditions are:
    a. The plugin interface is the null pointer.
    b. The plugin is OBJECT_ISSPLINE, then SplineObject.GetDimension will be called on the cache of the Spline object generator your plugin is implementing.
    c. Otherwise ObjectData::GetDimension will be called with the bounding box values which have been calculated so far.
  3. Other events and entities are also calling this same chain, and from what I can see, they all work properly.

Calling BaseObject::GetDimension indirectly from Python, the returned value 250, 50, 250 lines up with the value 500, 100, 500 in the Coordinate Manager. Note that GetDimension asks for the 'radii' of the bounding box, not its diameters. So, you must return half the value for each bounding box axis.

1a2c0e19-2a9e-4173-859f-ddb1a27a8d4b-image.png

And RoundedTube::GetDimension being called, setting these values, the break point is on the method scope exit, and shown are the returned values for rad:
ca66ebbf-712e-4db0-870e-4d840366c9cc-image.png

Cheers,
Ferdinand

Hi Ferdinand.
I'll explain each issue separately:

First. try to multiply *rad value by 10, in your example.
case 1: *rad = Vector(rady, rado + radx, rado + radx) *10; break;

Then when you try to select this object and use 'Frame Selected Elements' function in the viewport.
It will frame to the size of actual geometry not to the overridden size multiplied by 10.
So it ignores the override.

Hello @wtools3d,

This is a different issue as you claim in the title and body of your first posting, and your core claim, that GetDimension is being ignored, is not true. Here I multiply the values by 10.

114fc901-5564-4636-8217-72af9ba9915b-image.png

And as you can see, these values are respected in API calls as well as the Coordinate Manager and other elements of Cinema 4D using them.

f9394719-b7ee-40fd-92f8-2e59498662cc-image.png

Your issue seems to lie with the fact that the multiple frame commands as 'Frame Elements' and 'Frame Geometry' do not frame bounding boxes as yielded by the objects, but the actual geometry. This is not really an SDK issue and there are three things you can do:

  1. File a request with user support, that you either want the existing commands to be changed or a new one being added. Chances for this happening are low, because I think the behavior of the frame commands is intentional.
  2. Implement a 'Frame Bounding Box' command yourself, good framing is not trivial though (at least I would consider it non-trivial).
  3. Make your inflated bounding box actually to be true, by adding dummy points or null objects for the maxima of your 'fake' bounding box. This won't work for obvious reasons when you want your fake bounding box to be smaller than the bounding box of your geometry. It will also have the flaw that this will be reflected when the user converts your object with Current State to Object. With some message and cache hacking, you could fiddle things into place though. Here is a simple hack of RoundedTube::GetVirtualObjects:
   if (hh->GetBuildFlags() & BUILDFLAGS::ISOPARM)
    {
        lop = GenerateIsoLathe(cpadr, cpcnt, seg);
        if (!lop)
            goto error;
        SetAxis(lop, axis);
        ret->SetIsoparm(lop);
    }


    // --- Start of modifications of RoundedTube::GetVirtualObjects

    // I just added here a null object as the child of the cache root which
    // is 2500 units 'above' the root on the y-axis.
    
    BaseObject* null = BaseObject::Alloc(Onull);
    if (!null)
        goto error;

    null->InsertUnder(ret);

    Matrix ml = null->GetMl();
    ml.off = Vector(0, 2500, 0);
    null->SetMl(ml);

    // --- End of modifications of RoundedTube::GetVirtualObjects

    DeleteMem(cpadr);
    return ret;

error:
    DeleteMem(cpadr);
    blDelete(ret);
    return nullptr;
}

Which will frame then like this when pressing O:

751aca50-77a8-4ea5-9db1-8e1e71d2992e-image.png

Cheers,
Ferdinand

Now it's more clear.
I assumed behavior of the framing commands on wrong premise.

Maybe you could add some further explanation in the documentation where the overwritten bounding data is used in the cinema.

Thank you for your suggestions how to resolve this on my side!

Regards,
Viktor

Hello @wtools3d,

@wtools3d said in ObjectData::GetDimension() ignored?:

Maybe you could add some further explanation in the documentation where the overwritten bounding data is used in the cinema.

Yes, this is a good idea, I will do that.

Cheers,
Ferdinand