SetPrimaryPartCFrame does not always set the PrimaryPart's CFrame to the specified CFrame

Calling SetPrimaryPartCFrame on a Model does not always set the PrimaryPart’s CFrame exactly to what I specify. Rolling out a custom SetPrimaryPartCFrame implementation works fine, so it is something Roblox must be internally doing.

Repro:

local model = Instance.new("Model")
local pp = Instance.new("Part", model)
model.PrimaryPart = pp
pp.CFrame = CFrame.new(0, 0, 0, 1, -4.05845846e-09, 1.5118921e-17, -4.05845846e-09, 1, -7.4505806e-09, 1.5118921e-17, -7.4505806e-09, 1)
model:SetPrimaryPartCFrame(CFrame.new())
print(model:GetPrimaryPartCFrame() == CFrame.new()) -- false

Edit: please stop bringing up floating point imprecision, the wiki states that SetPrimaryPartCFrame sets the PrimaryPart to the specified CFrame. If the specified CFrame is the identity CFrame (i.e., its components are all either 0 or 1 and thus there is no imprecision issue) there shouldn’t be an issue with comparing them with ==. The ultimate issue here is the initial CFrame of the PrimaryPart is being taken into consideration when setting the final CFrame of the PrimaryPart when I can’t see why it should be.

Edit: the issue is in fact their implementation:
Roblox is not explicitly setting the PrimaryPart’s CFrame to the specified CFrame, instead they’re pretty much doing:
PrimaryPart.CFrame = NewCFrame * PrimaryPart.CFrame:ToObjectSpace(PrimaryPart.CFrame)
And you would expect that the expression PrimaryPart.CFrame:ToObjectSpace(PrimaryPart.CFrame) to be the identity CFrame but due to floating point imprecision this is not the case. This ideally shouldn’t be an issue because they should just do PrimaryPart.CFrame = NewCFrame as any sane person would assume (and do)…

4 Likes

It’s probably false due to floating point errors.

2 Likes

No, the wiki states that the PrimaryPart’s CFrame is set to the CFrame I specified. And the components of the identity CFrame are all integers so floating point imprecision is irrelevant to consider here.

1 Like

A CFrame’s arguments do not have to be integers, which means they are susceptible to floating point error.

Okay, but I already stated that it’s the identity CFrame not a CFrame with non integer components.

1 Like

Why don’t you just do

Model.PrimaryPart.CFrame = CFrame.new()
1 Like

You cannot always say they are exactly the same. Sometimes, there are floating point errors disjointing the numbers to the closest computable number in cases of decimals. This is due to limitations of machine codes with binary, if you were to use decimals(floats).

This is more apparent, if you place your parts [a large number] distance away from the origin(0, 0, 0).

And I still don’t get the idea of where the CFrame is placed in what specific orientation based on the input.

2 Likes

I cannot because other parts in the Model won’t be moved.

You cannot always say they are exactly the same. Sometimes, there are floating point errors disjointing the numbers to the closest computable number in cases of decimals. This is due to limitations of machine codes with binary, if you were to use decimals(floats).
Again, please read the thread.

The issue here is Roblox must be internally transforming the PrimaryPart after it’s set to the CFrame I specify.

2 Likes