@@ -236,6 +236,176 @@ public void TryGetOffsetFrom_FusesBothRigidFramesAcrossScalarFaces()
236236 Assert . Equal ( Vector3d . Zero , offset ) ;
237237 }
238238
239+ [ Fact ]
240+ public void TryGetOffsetFrom_SameFramePreservesCompositeLocalDifference ( )
241+ {
242+ Vector3d origin = new ( 7 , - 3 , 11 ) ;
243+ FixedPointAnchor first = new (
244+ origin ,
245+ FixedQuaternion . Identity ,
246+ new Vector3d ( 5 , 2 , - 4 ) ,
247+ new Vector3d ( - 2 , 3 , 1 ) ) ;
248+ FixedPointAnchor second = new (
249+ origin ,
250+ FixedQuaternion . Identity ,
251+ new Vector3d ( 1 , - 1 , 2 ) ,
252+ new Vector3d ( 3 , 1 , - 2 ) ) ;
253+
254+ Assert . True ( first . TryGetOffsetFrom ( second , out Vector3d offset ) ) ;
255+ Assert . Equal ( new Vector3d ( - 1 , 5 , - 3 ) , offset ) ;
256+ Assert . True ( first . TryGetScaledOffsetFrom (
257+ second ,
258+ - Fixed64 . Half ,
259+ out Vector3d scaled ) ) ;
260+ Assert . Equal ( new Vector3d (
261+ Fixed64 . Half ,
262+ - Fixed64 . FromFraction ( 5 , 2 ) ,
263+ Fixed64 . FromFraction ( 3 , 2 ) ) , scaled ) ;
264+ }
265+
266+ [ Fact ]
267+ public void TryGetOffsetFrom_IdentityFramesPreserveCompositeWorldDifference ( )
268+ {
269+ FixedPointAnchor first = new (
270+ new Vector3d ( 7 , - 3 , 11 ) ,
271+ FixedQuaternion . Identity ,
272+ new Vector3d ( 5 , 2 , - 4 ) ,
273+ new Vector3d ( - 2 , 3 , 1 ) ) ;
274+ FixedPointAnchor second = new (
275+ new Vector3d ( - 1 , 4 , 3 ) ,
276+ FixedQuaternion . Identity ,
277+ new Vector3d ( 1 , - 1 , 2 ) ,
278+ new Vector3d ( 3 , 1 , - 2 ) ) ;
279+
280+ Assert . True ( first . TryGetOffsetFrom ( second , out Vector3d offset ) ) ;
281+ Assert . Equal ( new Vector3d ( 7 , - 2 , 5 ) , offset ) ;
282+ Assert . True ( first . TryGetScaledOffsetFrom (
283+ second ,
284+ Fixed64 . Half ,
285+ out Vector3d scaled ) ) ;
286+ Assert . Equal ( new Vector3d (
287+ Fixed64 . FromFraction ( 7 , 2 ) ,
288+ - Fixed64 . One ,
289+ Fixed64 . FromFraction ( 5 , 2 ) ) , scaled ) ;
290+ }
291+
292+ [ Fact ]
293+ public void TryGetScaledOffsetFrom_SameIdentityFrameRoundsRawTiesToEven ( )
294+ {
295+ Fixed64 oneRaw = Fixed64 . FromRaw ( 1 ) ;
296+ Fixed64 threeRaw = Fixed64 . FromRaw ( 3 ) ;
297+ FixedPointAnchor first = new (
298+ Vector3d . Zero ,
299+ FixedQuaternion . Identity ,
300+ new Vector3d ( oneRaw , threeRaw , - threeRaw ) ) ;
301+ FixedPointAnchor second = new (
302+ Vector3d . Zero ,
303+ FixedQuaternion . Identity ,
304+ Vector3d . Zero ) ;
305+
306+ Assert . True ( first . TryGetScaledOffsetFrom (
307+ second ,
308+ Fixed64 . Half ,
309+ out Vector3d offset ) ) ;
310+ Assert . Equal ( new Vector3d (
311+ Fixed64 . Zero ,
312+ Fixed64 . FromRaw ( 2 ) ,
313+ Fixed64 . FromRaw ( - 2 ) ) , offset ) ;
314+ }
315+
316+ [ Fact ]
317+ public void TryGetOffsetFrom_IdentityFramesRetainIntermediateOverflowFallback ( )
318+ {
319+ FixedPointAnchor first = new (
320+ new Vector3d ( Fixed64 . MaxValue , Fixed64 . Zero , Fixed64 . Zero ) ,
321+ FixedQuaternion . Identity ,
322+ Vector3d . Right ,
323+ Vector3d . Left ) ;
324+ FixedPointAnchor second = new (
325+ Vector3d . Zero ,
326+ FixedQuaternion . Identity ,
327+ Vector3d . Zero ) ;
328+
329+ Assert . True ( first . TryGetOffsetFrom ( second , out Vector3d offset ) ) ;
330+ Assert . Equal (
331+ new Vector3d ( Fixed64 . MaxValue , Fixed64 . Zero , Fixed64 . Zero ) ,
332+ offset ) ;
333+ }
334+
335+ [ Fact ]
336+ public void TryGetOffsetFrom_SameRotatedFrameUsesCompleteLocalDifference ( )
337+ {
338+ Vector3d origin = new ( 7 , - 3 , 11 ) ;
339+ FixedQuaternion rotation =
340+ FixedQuaternion . FromAxisAngle ( Vector3d . Up , Fixed64 . HalfPi ) ;
341+ FixedPointAnchor first = new (
342+ origin ,
343+ rotation ,
344+ new Vector3d ( 5 , 2 , - 4 ) ,
345+ new Vector3d ( - 2 , 3 , 1 ) ) ;
346+ FixedPointAnchor second = new (
347+ origin ,
348+ rotation ,
349+ new Vector3d ( 1 , - 1 , 2 ) ,
350+ new Vector3d ( 3 , 1 , - 2 ) ) ;
351+
352+ Assert . True ( first . TryGetOffsetFrom ( second , out Vector3d offset ) ) ;
353+ Assert . Equal ( new Vector3d ( - 3 , 5 , 1 ) , offset ) ;
354+ Assert . True ( first . TryGetScaledOffsetFrom (
355+ second ,
356+ Fixed64 . Half ,
357+ out Vector3d scaled ) ) ;
358+ Assert . Equal ( new Vector3d (
359+ Fixed64 . FromFraction ( - 3 , 2 ) ,
360+ Fixed64 . FromFraction ( 5 , 2 ) ,
361+ Fixed64 . Half ) , scaled ) ;
362+ }
363+
364+ [ Fact ]
365+ public void TryGetOffsetFrom_SameRotatedFrameRetainsWideLocalFallback ( )
366+ {
367+ Fixed64 large = Fixed64 . FromRaw ( ( long . MaxValue / 5L ) * 3L ) ;
368+ FixedQuaternion rotation =
369+ FixedQuaternion . FromAxisAngle ( Vector3d . Up , Fixed64 . PiOver4 ) ;
370+ FixedPointAnchor first = new (
371+ Vector3d . Zero ,
372+ rotation ,
373+ new Vector3d ( large , Fixed64 . Zero , Fixed64 . Zero ) ) ;
374+ FixedPointAnchor second = new (
375+ Vector3d . Zero ,
376+ rotation ,
377+ new Vector3d ( - large , Fixed64 . Zero , Fixed64 . Zero ) ) ;
378+
379+ Assert . False ( Vector3d . TrySubtract (
380+ first . LocalPoint ,
381+ second . LocalPoint ,
382+ out _ ) ) ;
383+ Assert . True ( first . TryGetOffsetFrom ( second , out Vector3d offset ) ) ;
384+ Assert . Equal ( new Vector3d (
385+ Fixed64 . FromRaw ( 7826290728543493829L ) ,
386+ Fixed64 . Zero ,
387+ Fixed64 . FromRaw ( - 7826290661855844679L ) ) , offset ) ;
388+ }
389+
390+ [ Fact ]
391+ public void TryGetScaledOffsetFrom_SameIdentityFrameRejectsFinalOverflow ( )
392+ {
393+ FixedPointAnchor first = new (
394+ Vector3d . Zero ,
395+ FixedQuaternion . Identity ,
396+ new Vector3d ( Fixed64 . MaxValue , Fixed64 . Zero , Fixed64 . Zero ) ) ;
397+ FixedPointAnchor second = new (
398+ Vector3d . Zero ,
399+ FixedQuaternion . Identity ,
400+ Vector3d . Zero ) ;
401+
402+ Assert . False ( first . TryGetScaledOffsetFrom (
403+ second ,
404+ Fixed64 . Two ,
405+ out Vector3d offset ) ) ;
406+ Assert . Equal ( default , offset ) ;
407+ }
408+
239409 [ Fact ]
240410 public void TryGetPoint_RejectsUnrepresentableWorldCoordinate ( )
241411 {
0 commit comments