@@ -397,6 +397,8 @@ MCTypeInfoRef kMCCanvasGradientStopRangeErrorTypeInfo;
397397MCTypeInfoRef kMCCanvasGradientStopOrderErrorTypeInfo ;
398398MCTypeInfoRef kMCCanvasGradientTypeErrorTypeInfo ;
399399
400+ MCTypeInfoRef kMCCanvasPathPointListFormatErrorTypeInfo ;
401+
400402// //////////////////////////////////////////////////////////////////////////////
401403
402404// Constant refs
@@ -1365,85 +1367,51 @@ void MCCanvasTransformGetInverse(MCCanvasTransformRef p_transform, MCCanvasTrans
13651367 MCCanvasTransformMake (MCGAffineTransformInvert (*MCCanvasTransformGet (p_transform)), r_transform);
13661368}
13671369
1368- // T = Tscale * Trotate * Tskew * Ttranslate
1370+ // T = Ttranslate * Trotate * Tskew * Tscale
13691371
13701372MCGAffineTransform MCCanvasTransformCompose (const MCGPoint &p_scale, MCCanvasFloat p_rotation, const MCGPoint &p_skew, const MCGPoint &p_translation)
13711373{
13721374 MCGAffineTransform t_transform;
13731375 t_transform = MCGAffineTransformMakeScale (p_scale.x , p_scale.y );
1374- t_transform = MCGAffineTransformConcat ( MCGAffineTransformMakeRotation ( MCCanvasRadiansToDegrees (p_rotation)), t_transform );
1375- t_transform = MCGAffineTransformConcat ( MCGAffineTransformMakeSkew (p_skew. x , p_skew. y ), t_transform );
1376- t_transform = MCGAffineTransformConcat ( MCGAffineTransformMakeTranslation ( p_translation.x , p_translation.y ), t_transform );
1376+ t_transform = MCGAffineTransformPreSkew (t_transform, p_skew. x , p_skew. y );
1377+ t_transform = MCGAffineTransformPreRotate (t_transform, MCCanvasAngleFromRadians (p_rotation) );
1378+ t_transform = MCGAffineTransformPreTranslate (t_transform, p_translation.x , p_translation.y );
13771379
13781380 return t_transform;
13791381}
13801382
1381- /*
1382- * Ttranslate:
1383- * / 1 0 tx \
1384- * | 0 1 ty |
1385- * \ 0 0 1 /
1386- *
1387- * Tscale * Trotate * Tskew:
1388- * / a c \ / 1 Skew \ / Cos(r) -Sin(r) \ / ScaleX 0 \ / -ScaleX * Skew * Sin(r) + ScaleX * Cos(r) ScaleY * Skew * Cos(r) + ScaleY * Sin(r) \
1389- * \ b d / = \ 0 1 / * \ Sin(r) Cos(r) / * \ 0 ScaleY / = \ -ScaleX * Sin(r) ScaleY * Cos(r) /
1390- */
13911383bool MCCanvasTransformDecompose (const MCGAffineTransform &p_transform, MCGPoint &r_scale, MCCanvasFloat &r_rotation, MCGPoint &r_skew, MCGPoint &r_translation)
13921384{
1393- MCGFloat t_r, t_skew ;
1394- MCGPoint t_scale, t_trans ;
1385+ MCGAffineTransform t_transform ;
1386+ t_transform = p_transform ;
13951387
1396- t_trans = MCGPointMake (p_transform.tx , p_transform.ty );
1388+ MCGPoint t_scale, t_skew, t_translation;
1389+ MCCanvasFloat t_rotation;
1390+
1391+ // Remove translation component.
1392+ t_translation = MCGPointMake (t_transform.tx , t_transform.ty );
1393+ t_transform.tx = t_transform.ty = 0 ;
13971394
1398- // if b == 0, take r to be 0 radians
1399- if (p_transform.b == 0 )
1400- {
1401- t_r = 0 ;
1402- // a == ScaleX, d == ScaleY
1403- t_scale = MCGPointMake (p_transform.a , p_transform.d );
1404- // c = ScaleY * Skew => Skew = c / ScaleY => Skew = c / d
1405- if (p_transform.d == 0 )
1406- return false ;
1407- t_skew = p_transform.c / p_transform.d ;
1408- }
1409- // if d == 0, take r to be -pi / 2 radians
1410- else if (p_transform.d == 0 )
1411- {
1412- t_r = M_PI / 2 ;
1413- // b == -ScaleX, c == ScaleY
1414- t_scale = MCGPointMake (-p_transform.b , p_transform.c );
1415- // a == -ScaleX * Skew => Skew == a / -ScaleX => Skew = a / b
1416- if (p_transform.b == 0 )
1417- return false ;
1418- t_skew = p_transform.a / p_transform.b ;
1419- }
1420- else
1421- {
1422- // Skew^2 + (a/b - c/d) * Skew + (1 + a/b * c/d) = 0
1423- MCGFloat t_a_div_b, t_c_div_d;
1424- t_a_div_b = p_transform.a / p_transform.b ;
1425- t_c_div_d = p_transform.c / p_transform.d ;
1426-
1427- MCGFloat t_x1, t_x2;
1428- if (!MCSolveQuadraticEqn (1 , t_a_div_b - t_c_div_d, 1 + t_a_div_b * t_c_div_d, t_x1, t_x2))
1429- return false ;
1430-
1431- // choose skew with smallest absolute value
1432- if (MCAbs (t_x1) < MCAbs (t_x2))
1433- t_skew = t_x1;
1434- else
1435- t_skew = t_x2;
1436-
1437- // Tan(r) = c/d - Skew
1438- t_r = atan (t_c_div_d - t_skew);
1439-
1440- t_scale = MCGPointMake (-p_transform.b / sinf (t_r), p_transform.d / cosf (t_r));
1441- }
1395+ // Calculate rotation of transformed unit vector
1396+ MCGPoint t_point;
1397+ t_point = MCGPointApplyAffineTransform (MCGPointMake (1 , 0 ), t_transform);
1398+
1399+ t_rotation = atan2f (t_point.y , t_point.x );
1400+
1401+ // remove rotation component from transform by applying rotation in the opposite direction
1402+ t_transform = MCGAffineTransformPreRotate (t_transform, MCCanvasAngleFromRadians (-t_rotation));
1403+
1404+ if (t_transform.a == 0 || t_transform.d == 0 )
1405+ return false ;
1406+
1407+ // scale and skew can now be obtained directly from the transform
1408+ t_scale = MCGPointMake (t_transform.a , t_transform.d );
1409+ t_skew = MCGPointMake (t_transform.c / t_transform.d , t_transform.b / t_transform.a );
14421410
14431411 r_scale = t_scale;
1444- r_rotation = -t_r; // calculations assume y increases upwards producing a rotation in the wrong direction, so take the negative.
1445- r_skew = MCGPointMake ( t_skew, 0 ) ;
1446- r_translation = t_trans ;
1412+ r_rotation = t_rotation;
1413+ r_skew = t_skew;
1414+ r_translation = t_translation ;
14471415
14481416 return true ;
14491417}
@@ -1574,7 +1542,7 @@ void MCCanvasTransformSetTranslationAsList(MCProperListRef p_translation, MCCanv
15741542
15751543void MCCanvasTransformConcat (MCCanvasTransformRef &x_transform, const MCGAffineTransform &p_transform)
15761544{
1577- MCCanvasTransformSetMCGAffineTransform (MCGAffineTransformConcat (p_transform, *MCCanvasTransformGet (x_transform)), x_transform);
1545+ MCCanvasTransformSetMCGAffineTransform (MCGAffineTransformConcat (*MCCanvasTransformGet (x_transform), p_transform ), x_transform);
15781546}
15791547
15801548void MCCanvasTransformConcat (MCCanvasTransformRef &x_transform, MCCanvasTransformRef p_transform)
@@ -1629,6 +1597,14 @@ void MCCanvasTransformSkew(MCCanvasTransformRef &x_transform, MCProperListRef p_
16291597 MCCanvasTransformSkew (x_transform, t_skew.x , t_skew.y );
16301598}
16311599
1600+ void MCCanvasTransformMultiply (MCCanvasTransformRef p_left, MCCanvasTransformRef p_right, MCCanvasTransformRef &r_transform)
1601+ {
1602+ MCGAffineTransform t_transform;
1603+ t_transform = MCGAffineTransformConcat (*MCCanvasTransformGet (p_left), *MCCanvasTransformGet (p_right));
1604+
1605+ MCCanvasTransformMake (t_transform, r_transform);
1606+ }
1607+
16321608// //////////////////////////////////////////////////////////////////////////////
16331609
16341610// Image
@@ -2573,7 +2549,7 @@ void MCCanvasGradientTransformToPoints(const MCGAffineTransform &p_transform, MC
25732549 r_via = MCGPointApplyAffineTransform (MCGPointMake (0 , 1 ), p_transform);
25742550}
25752551
2576- bool MCCanvasGradientTransformFromPoints (const MCGPoint &p_from, const MCGPoint &p_to, const MCGPoint &p_via, MCGAffineTransform &r_transform)
2552+ void MCCanvasGradientTransformFromPoints (const MCGPoint &p_from, const MCGPoint &p_to, const MCGPoint &p_via, MCGAffineTransform &r_transform)
25772553{
25782554 MCGAffineTransform t_transform;
25792555 t_transform . a = p_to . x - p_from . x;
@@ -2584,8 +2560,6 @@ bool MCCanvasGradientTransformFromPoints(const MCGPoint &p_from, const MCGPoint
25842560 t_transform . ty = p_from . y;
25852561
25862562 r_transform = t_transform;
2587-
2588- return true ;
25892563}
25902564
25912565void MCCanvasGradientGetTransform (MCCanvasGradientRef p_gradient, MCGAffineTransform &r_transform)
@@ -2614,10 +2588,7 @@ void MCCanvasGradientGetPoints(MCCanvasGradientRef p_gradient, MCGPoint &r_from,
26142588void MCCanvasGradientSetPoints (MCCanvasGradientRef &x_gradient, const MCGPoint &p_from, const MCGPoint &p_to, const MCGPoint &p_via)
26152589{
26162590 MCGAffineTransform t_transform;
2617- if (!MCCanvasGradientTransformFromPoints (p_from, p_to, p_via, t_transform))
2618- {
2619- // TODO - throw error
2620- }
2591+ MCCanvasGradientTransformFromPoints (p_from, p_to, p_via, t_transform);
26212592 MCCanvasGradientSetTransform (x_gradient, t_transform);
26222593}
26232594
@@ -3129,7 +3100,7 @@ bool MCCanvasPointsListToMCGPoints(MCProperListRef p_points, MCGPoint *r_points)
31293100 }
31303101 else
31313102 {
3132- // TODO - throw point type error
3103+ MCCanvasThrowError ( kMCCanvasPathPointListFormatErrorTypeInfo );
31333104 t_success = false ;
31343105 }
31353106 }
@@ -5665,6 +5636,9 @@ void MCCanvasErrorsInitialize()
56655636 kMCCanvasGradientTypeErrorTypeInfo = nil;
56665637 /* UNCHECKED */ MCCanvasCreateNamedErrorType (MCNAME (" com.livecode.canvas.GradientTypeError" ), MCSTR (" Unrecognised gradient type." ), kMCCanvasGradientTypeErrorTypeInfo );
56675638
5639+ kMCCanvasPathPointListFormatErrorTypeInfo = nil;
5640+ /* UNCHECKED */ MCCanvasCreateNamedErrorType (MCNAME (" com.livecode.canvas.PathPointListFormatError" ), MCSTR (" Invalid value in list of points." ), kMCCanvasPathPointListFormatErrorTypeInfo );
5641+
56685642}
56695643
56705644void MCCanvasErrorsFinalize ()
@@ -5898,7 +5872,7 @@ bool MCCanvasEffectTypeToString(MCCanvasEffectType p_type, MCStringRef &r_string
58985872
58995873bool MCCanvasEffectTypeFromString (MCStringRef p_string, MCCanvasEffectType &r_type)
59005874{
5901- return _mcenumfromstring<MCCanvasEffectType, kMCGFillRuleCount >(s_effect_type_map, p_string, r_type);
5875+ return _mcenumfromstring<MCCanvasEffectType, _MCCanvasEffectTypeCount >(s_effect_type_map, p_string, r_type);
59025876}
59035877
59045878bool MCCanvasFillRuleToString (MCGFillRule p_fill_rule, MCStringRef &r_string)
0 commit comments