Chapter 35 · ShapeEx 路径构建

矩阵进阶:斜切/逆/变换点

斜切(Skew)、逆矩阵(Invert)、变换点/向量/矩形边界,以及描边缩放因子。

35

API 速查

函数说明
int xgeShapeExMatrixSkew(xge_shape_ex_matrix_t* pMatrix, float fXRadians, float fYRadians)追加斜切
int xgeShapeExMatrixInvert(xge_shape_ex_matrix_t* pOut, const ...* pMatrix)求逆矩阵
int xgeShapeExMatrixPoint(xge_vec2_t* pOut, const ...* pMatrix, xge_vec2_t tPoint)变换点(含平移)
int xgeShapeExMatrixVector(xge_vec2_t* pOut, const ...* pMatrix, xge_vec2_t tVector)变换向量(忽略平移)
int xgeShapeExMatrixRectBounds(xge_rect_t* pOut, const ...* pMatrix, xge_rect_t tRect)变换矩形的 AABB 包围盒
int xgeShapeExMatrixStrokeScale(float* pScale, const ...* pMatrix)获取描边缩放因子

编译本章示例

gcc -O2 -I. -o ch35.exe ch35_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch35.exe

示例 1:斜切效果

xge_shape_ex_matrix_t mat;
xgeShapeExMatrixIdentity(&mat);

// X 方向斜切 30°
xgeShapeExMatrixSkew(&mat, 3.14159265f/6.0f, 0);

// 应用到 ShapeEx
xgeShapeExTransformSet(shape, &mat);

示例 2:逆变换(屏幕→局部坐标)

// 已知世界变换
xge_shape_ex_matrix_t world;
xgeShapeExMatrixIdentity(&world);
xgeShapeExMatrixTranslate(&world, 200, 100);
xgeShapeExMatrixRotate(&world, 0.5f);

// 求逆
xge_shape_ex_matrix_t inv;
xgeShapeExMatrixInvert(&inv, &world);

// 将屏幕点转换到局部坐标
xge_vec2_t screen = { 350, 250 };
xge_vec2_t local;
xgeShapeExMatrixPoint(&local, &inv, screen);

示例 3:变换矩形边界

xge_rect_t src = { 0, 0, 100, 50 };
xge_shape_ex_matrix_t mat;
xgeShapeExMatrixIdentity(&mat);
xgeShapeExMatrixRotate(&mat, 3.14159265f/4.0f);

// 获取旋转后的轴对齐包围盒
xge_rect_t bounds;
xgeShapeExMatrixRectBounds(&bounds, &mat, src);
// bounds 比 src 大(旋转后外接矩形变大)

完整代码

将以下代码保存为 ch35_main.c,编译后运行即可看到斜切、逆变换与边界计算效果:

#include "xge.h"

static xge_shape_ex g_rect = NULL;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);

    // 斜切效果
    xge_shape_ex_matrix_t skew;
    xgeShapeExMatrixIdentity(&skew);
    xgeShapeExMatrixTranslate(&skew, 80, 80);
    xgeShapeExMatrixSkew(&skew, 3.14159265f/6.0f, 0);
    xgeShapeExTransformSet(g_rect, &skew);
    xgeShapeExFillColor(g_rect, 0x4FD8C2FF);
    xgeShapeExDraw(g_rect, 0.25f);

    // 旋转 45° + 显示 AABB 包围盒
    xge_shape_ex_matrix_t rot;
    xgeShapeExMatrixIdentity(&rot);
    xgeShapeExMatrixTranslate(&rot, 450, 200);
    xgeShapeExMatrixRotate(&rot, 3.14159265f/4.0f);
    xgeShapeExTransformSet(g_rect, &rot);
    xgeShapeExFillColor(g_rect, 0xFFB454FF);
    xgeShapeExDraw(g_rect, 0.25f);

    // 计算并绘制 AABB 包围盒
    xge_rect_t src = { 0, 0, 150, 100 };
    xge_rect_t bounds;
    xgeShapeExMatrixRectBounds(&bounds, &rot, src);
    bounds.fX += 450; bounds.fY += 200;
    xgeShapeRectStroke(bounds, 1.0f, 0xFF6B5E80);

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch35 - Matrix Advanced";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    xgeShapeExCreate(&g_rect);
    xgeShapeExMoveTo(g_rect, 0, 0);
    xgeShapeExLineTo(g_rect, 150, 0);
    xgeShapeExLineTo(g_rect, 150, 100);
    xgeShapeExLineTo(g_rect, 0, 100);
    xgeShapeExClose(g_rect);

    xgeRun(onFrame, NULL);

    xgeShapeExDestroy(g_rect);
    xgeUnit();
    return 0;
}

代码讲解

  • Skew 斜切:X 方向斜切 30°,矩形变为平行四边形,模拟斜体效果。
  • RectBounds:计算旋转后矩形的轴对齐包围盒(AABB),用于碰撞检测粗筛。
  • Point vs Vector:Point 含平移,Vector 忽略平移——变换方向/法线时用 Vector。
  • 逆矩阵:M⁻¹ 可将世界坐标转回局部坐标,用于鼠标拾取。

要点与陷阱

  • Point vs Vector:Point 包含平移(E,F),Vector 忽略平移——用于变换方向/法线。
  • 逆矩阵可能失败:行列式为 0(退化矩阵)时 Invert 返回非 0。
  • RectBounds 是 AABB:旋转后的矩形用轴对齐包围盒表示,面积 ≥ 原矩形。
  • StrokeScale:返回矩阵的平均缩放因子,用于 non-scaling stroke 计算。
  • Skew 参数:fXRadians 控制 X 方向倾斜,fYRadians 控制 Y 方向倾斜。

进阶练习

  1. 实现"斜切文字"效果:对一组矩形应用 Skew 模拟斜体。
  2. 验证 M × M⁻¹ = Identity:对随机矩阵求逆后相乘,检查结果是否接近单位矩阵。
  3. 用 RectBounds 实现旋转图形的碰撞检测粗筛(AABB 相交测试)。
矩阵进阶:斜切/逆/变换点效果
图:矩阵进阶:斜切/逆/变换点渲染效果