Retrieve the current Unit and listen to changes
-
Hello, I need a way to retrieve not only the current unit of the editor and the world matrices, but also to get notified in my plugin, when the user changes the unit in the settings window, because then I will also need to re-calculate the data generated by my plugin to fit the new unit. Is there a way to subscribe to those type of changes, or would I have to write a more complex system to always stay up-to-date with the latest unit settings?
The default unit of the editor should be centimeters I believe, but most use cases of my plugin would probably be millimeters, or even nanometers sometimes.Thanks for any help!
-
Hi @Cankar001 you do not have to do anything as long as you define your parameter as a unit then it will respect the one in Cinema 4D and automatically adapt.
If your plugin is a GeDialog, then you need to call SetMeter and if you are working with description you need to set DESC_UNIT to DESC_UNIT_METER. While the symbol indicate meter, they will respect the settings defined in the document and adapt accordingly.
If you do not want to use the default system, then you will have to do everything yourself, and track yourself the change. But here it depend too much on the type of your plugin to guide you, so please tell us a bit more about it, and most important what is your UI.
Cheers,
Maxime. -
Hi Maxime, I don't have any UI in my plugin, as the control flow is controlled pureley over a websocket. The plugin calculates some data, when the command is received over the websocket and displays some debug ui in the rendering viewport (basic line rendering), but that's about it so I don't have any plugin setting or UI panel. Is it possible to get notified by a core message about the unit change?
-
Hi @Cankar001 there is no such message, so you have to track it yourself.
The best way would be to use a MessageData MessageData to either
create a timer that will periodically (maybe each second) check the value stored in the document or react to EVMSG_CHANGE and also check the value stored in the document.Cheers,
Maxime. -
@m_adam And how exactly would I retrieve and change the unit itself? I tried it this way:
Bool UnitChangeDetector::CoreMessage(Int32 id, const BaseContainer& bc) { if (id == EVMSG_CHANGE) { BaseDocument* doc = GetActiveDocument(); if (!doc) { ApplicationOutput("Failed to get active document!"); return true; } BaseContainer data = doc->GetData(DOCUMENTSETTINGS::GENERAL); data.SetInt32(DOCUMENT_DOCUNIT, (Int32)DOCUMENT_UNIT::KM); doc->SetData(DOCUMENTSETTINGS::GENERAL, data); } return true; }
(Only for testing of course, the final version would not look like this)
But when I check the settings in Edit > Program Settings > Units > Display it still says Centimeters instead of the expected kilometers.
-
Hi what you describe (Edit > Program Settings > Units > Display) is only the display of the unit in the whole Cinema 4D interface. Not the actual unit of the document which can be found by pressing CTRL+D -> Project -> Scale and which is actually changed by the code you provided.
So do you really want to change/listen to the Display unit and not the actual unit?
Cheers,
Maxime. -
@m_adam Thanks for the clarification! What I am trying to achieve is that the whole units for the user get changed. When I change the display setting manually, all the units in the UI also change and the values get re-calculated for the selected unit. My high level goal is, that my plugin also should do these re-calculations, once the user changes the unit in the settings, because right now my plugin would show the wrong values, when the unit gets changed from the default unit. So yes I would need to listen to the display unit I think, because the calculations should be done when the user wanted the units to change
-
Hey @Cankar001 I frankly do not understand what you are doing and why you would need that. Since you told me previously that you do not have any UI in your plugin but you told us "Would show wrong values", so which values are you talking about?
Matrices, Vectors, float in Cinema 4D are unit less and will adapt properly according to the document unit and not the displayed unit. Display unit are more or less just noise and does not indicate anything regarding the actual size of an object. For more information about Display unit vs document unit please read How Do I Change the Units Used By Cinema 4D To Something Other Than Centimeters? .So if you want more help then you will need to share with us some code to demonstrate the issue since we do not really understand the reasoning of why you will want to do that (not saying you do not have a valid reason for doing it, but we do not understand it). If it's private code you can send it to us at [email protected].
With that's said here is how you retrieve and set the preference:BasePlugin* bp = FindPlugin(PREFS_UNITS, cinema::PLUGINTYPE::PREFS); if (bp == nullptr) return; /* Possible Values PREF_UNITS_BASIC_KM = 1, PREF_UNITS_BASIC_M = 2, PREF_UNITS_BASIC_CM = 3, PREF_UNITS_BASIC_MM = 4, PREF_UNITS_BASIC_MICRO = 5, PREF_UNITS_BASIC_NM = 6, PREF_UNITS_BASIC_MILE = 7, PREF_UNITS_BASIC_YARD = 8, PREF_UNITS_BASIC_FOOT = 9, PREF_UNITS_BASIC_INCH = 10, */ GeData unitValue; bp->GetParameter(CreateDescID(PREF_UNITS_BASIC), unitValue, cinema::DESCFLAGS_GET::NONE); Int32 uValue = unitValue.GetInt32(); bp->SetParameter(CreateDescID(PREF_UNITS_BASIC), PREF_UNITS_BASIC_KM, cinema::DESCFLAGS_SET::NONE);
Again there is no such event so it will be on you to have a timer that check if the value changed or not.
Cheers,
Maxime. -
@m_adam Thanks for your quick reply! I wrote a more detailed mail to the mail address you provided
-
Hello @Cankar001,
I am going to answer here in the forum, as there are no confidential aspects here. As Maxime pointed out in his last posting, Cinema 4D is unitless. Find below a video drives home that point.
- When you want to draw unit values into the viewport, you will have to do some manual conversion. You would have to get the values from both the preferences and document settings and write a custom function which accordingly scales the raw API value and applies a unit abbreviation.
- When you want to get informed about either the system unit (the value in the prefs) or the document scale having changed, you would have to listen for
EVMSG_CHANGE
as Maxime explained and check the values against a value you have cached. I would not recommend using a timer (instead ofEVMSG_CHANGE
), unless you set it to a high value like 1000 ms.
Cheers,
Ferdinand