@@ -370,6 +370,50 @@ public function testCalculateArcCenterRespectsSweepDirection(): void
370370 );
371371 }
372372
373+ public function testCalculateArcCenterMatchesExpectedRotatedNormalizedCenter (): void
374+ {
375+ $ converter = new SvgArcConverter ();
376+ $ params = new ArcParams (
377+ 0.0 ,
378+ 10.0 ,
379+ 60.0 ,
380+ 30.0 ,
381+ 38.77015604817706 ,
382+ 20.677416559027762 ,
383+ cos (deg2rad (45.0 )),
384+ sin (deg2rad (45.0 )),
385+ 1 ,
386+ 1 ,
387+ );
388+
389+ $ center = self ::invokePrivateMethod ($ converter , 'calculateArcCenter ' , [$ params ]);
390+
391+ self ::assertEqualsWithDelta (29.999999923071595 , $ center [0 ], 0.0001 );
392+ self ::assertEqualsWithDelta (19.99999972004405 , $ center [1 ], 0.0001 );
393+ }
394+
395+ public function testCalculateArcCenterFallsBackToMidpointBelowDenominatorTolerance (): void
396+ {
397+ $ converter = new SvgArcConverter ();
398+ $ params = new ArcParams (
399+ 0.0 ,
400+ 0.0 ,
401+ -1.0e-6 ,
402+ 0.0 ,
403+ 1.0 ,
404+ 1.0 ,
405+ 1.0 ,
406+ 0.0 ,
407+ 0 ,
408+ 1 ,
409+ );
410+
411+ $ center = self ::invokePrivateMethod ($ converter , 'calculateArcCenter ' , [$ params ]);
412+
413+ self ::assertEqualsWithDelta (-5.0e-7 , $ center [0 ], 1.0e-12 );
414+ self ::assertEqualsWithDelta (0.0 , $ center [1 ], 1.0e-12 );
415+ }
416+
373417 public function testCalculateArcAnglesReturnsExpectedSweepAdjustedDelta (): void
374418 {
375419 $ converter = new SvgArcConverter ();
@@ -393,6 +437,61 @@ public function testCalculateArcAnglesReturnsExpectedSweepAdjustedDelta(): void
393437 self ::assertEqualsWithDelta (M_PI , $ clockwiseAngles [1 ], 0.0001 );
394438 }
395439
440+ public function testCalculateArcAnglesMatchesExpectedRotatedNormalizedValues (): void
441+ {
442+ $ converter = new SvgArcConverter ();
443+ $ params = new ArcParams (
444+ 0.0 ,
445+ 10.0 ,
446+ 60.0 ,
447+ 30.0 ,
448+ 38.77015604817706 ,
449+ 20.677416559027762 ,
450+ cos (deg2rad (45.0 )),
451+ sin (deg2rad (45.0 )),
452+ 1 ,
453+ 1 ,
454+ );
455+
456+ $ angles = self ::invokePrivateMethod (
457+ $ converter ,
458+ 'calculateArcAngles ' ,
459+ [$ params , 29.999999923071595 , 19.99999972004405 ],
460+ );
461+
462+ self ::assertEqualsWithDelta (2.388441372627599 , $ angles [0 ], 0.0001 );
463+ self ::assertEqualsWithDelta (M_PI , $ angles [1 ], 0.0001 );
464+ }
465+
466+ public function testCalculateArcCenterAndAnglesMatchExpectedAsymmetricValues (): void
467+ {
468+ $ converter = new SvgArcConverter ();
469+ $ params = new ArcParams (
470+ 0.0 ,
471+ 0.0 ,
472+ 25.0 ,
473+ 8.0 ,
474+ 13.566066509534181 ,
475+ 10.174549882150636 ,
476+ cos (deg2rad (35.0 )),
477+ sin (deg2rad (35.0 )),
478+ 1 ,
479+ 0 ,
480+ );
481+
482+ $ center = self ::invokePrivateMethod ($ converter , 'calculateArcCenter ' , [$ params ]);
483+ $ angles = self ::invokePrivateMethod (
484+ $ converter ,
485+ 'calculateArcAngles ' ,
486+ [$ params , $ center [0 ], $ center [1 ]],
487+ );
488+
489+ self ::assertEqualsWithDelta (12.499999988863545 , $ center [0 ], 0.0001 );
490+ self ::assertEqualsWithDelta (4.000000104332266 , $ center [1 ], 0.0001 );
491+ self ::assertEqualsWithDelta (2.7489504213408784 , $ angles [0 ], 0.0001 );
492+ self ::assertEqualsWithDelta (-M_PI , $ angles [1 ], 0.0001 );
493+ }
494+
396495 public function testGenerateArcCurvesUsesSingleSegmentBelowNinetyDegrees (): void
397496 {
398497 $ converter = new SvgArcConverter ();
@@ -417,6 +516,79 @@ public function testGenerateArcCurvesUsesSingleSegmentBelowNinetyDegrees(): void
417516 );
418517 }
419518
519+ public function testGenerateArcCurvesReturnsSinglePointCurveWhenDeltaAngleIsZero (): void
520+ {
521+ $ converter = new SvgArcConverter ();
522+
523+ $ curves = self ::invokePrivateMethod (
524+ $ converter ,
525+ 'generateArcCurves ' ,
526+ [0.0 , 0.0 , 10.0 , 10.0 , 1.0 , 0.0 , 0.0 , 0.0 ],
527+ );
528+
529+ self ::assertCount (1 , $ curves );
530+ self ::assertCurveMatches ([10.0 , 0.0 , 10.0 , 0.0 , 10.0 , 0.0 ], $ curves [0 ]);
531+ }
532+
533+ public function testGenerateArcCurvesMatchesExpectedRotatedQuarterSegment (): void
534+ {
535+ $ converter = new SvgArcConverter ();
536+
537+ $ curves = self ::invokePrivateMethod (
538+ $ converter ,
539+ 'generateArcCurves ' ,
540+ [
541+ 3.0 ,
542+ -2.0 ,
543+ 10.0 ,
544+ 6.0 ,
545+ cos (deg2rad (45.0 )),
546+ sin (deg2rad (45.0 )),
547+ 0.0 ,
548+ M_PI / 4.0 ,
549+ ],
550+ );
551+
552+ self ::assertCount (1 , $ curves );
553+ self ::assertCurveMatches (
554+ [8.946281087094862 , 6.195854536636088 , 7.120918187930419 , 6.530229546982604 , 5.0 , 6.0 ],
555+ $ curves [0 ],
556+ );
557+ }
558+
559+ public function testGenerateArcCurvesMatchesExpectedRotatedQuarterSegmentWithNonZeroStart (): void
560+ {
561+ $ converter = new SvgArcConverter ();
562+
563+ $ curves = self ::invokePrivateMethod (
564+ $ converter ,
565+ 'generateArcCurves ' ,
566+ [
567+ 3.0 ,
568+ -2.0 ,
569+ 10.0 ,
570+ 6.0 ,
571+ cos (deg2rad (45.0 )),
572+ sin (deg2rad (45.0 )),
573+ M_PI / 4.0 ,
574+ M_PI / 4.0 ,
575+ ],
576+ );
577+
578+ self ::assertCount (1 , $ curves );
579+ self ::assertCurveMatches (
580+ [
581+ 2.8790818120695802 ,
582+ 5.469770453017396 ,
583+ 0.632003854165071 ,
584+ 4.117285228403642 ,
585+ -1.2426406871192843 ,
586+ 2.242640687119286 ,
587+ ],
588+ $ curves [0 ],
589+ );
590+ }
591+
420592 public function testGenerateArcCurvesSplitsLargerAnglesIntoExpectedSegments (): void
421593 {
422594 $ converter = new SvgArcConverter ();
@@ -452,6 +624,43 @@ public function testGenerateArcCurvesSplitsLargerAnglesIntoExpectedSegments(): v
452624 );
453625 }
454626
627+ public function testGenerateArcCurvesMatchesExpectedRotatedThreeQuarterSegments (): void
628+ {
629+ $ converter = new SvgArcConverter ();
630+
631+ $ curves = self ::invokePrivateMethod (
632+ $ converter ,
633+ 'generateArcCurves ' ,
634+ [
635+ 3.0 ,
636+ -2.0 ,
637+ 10.0 ,
638+ 6.0 ,
639+ cos (deg2rad (45.0 )),
640+ sin (deg2rad (45.0 )),
641+ 0.0 ,
642+ 3.0 * M_PI / 4.0 ,
643+ ],
644+ );
645+
646+ self ::assertCount (2 , $ curves );
647+ self ::assertCurveMatches (
648+ [
649+ 8.358540583851704 ,
650+ 6.783595039879246 ,
651+ 5.078595495120528 ,
652+ 6.607261689108819 ,
653+ 1.7862916061018566 ,
654+ 4.625669395360115 ,
655+ ],
656+ $ curves [0 ],
657+ );
658+ self ::assertCurveMatches (
659+ [-1.506012282916814 , 2.64407710161141 , -4.192706922736574 , -0.7708276909462963 , -5.0 , -3.9999999999999987 ],
660+ $ curves [1 ],
661+ );
662+ }
663+
455664 #[DataProvider('provideArcScenarios ' )]
456665 public function testArcToBezierCurvesGeneratesExpectedCurveShape (
457666 float $ fromX ,
0 commit comments