当前位置: 首页 > news >正文

UVa12303 Composite Transformations

UVa12303 Composite Transformations

  • 题目链接
  • 题意
    • 输入格式
    • 输出格式
  • 分析
  • AC 代码

题目链接

  UVa12303 Composite Transformations

题意

  空间中有n个点和m个平面,你的任务是按顺序向它们施加t个变换,输出每个点的最终位置和每个平面的最终方程。一共有3种变换,如表下表所示。

变换说明
TRANSLATE a b c点(x,y,z)变成(x+a,y+b,z+c)
ROTATE a b c theta把每个点旋转theta 度。旋转轴是向量(a,b,c),并且穿过原点。当旋转轴指向你时,旋转看上去是逆时针的
SCALE a b c点(x,y,z)变成(ax,by,cz)

输入格式

  输入只有一组数据。第一行是3个整数n, m, t(1≤n,m≤50 000,1≤t≤1 000);以下n行每行包含一个点的坐标;用以下m行每行4个整数a, b, c, d,描述一个平面ax+by+cz+d=0(a, b, c 不全为0);以下t行描述各个操作。操作中的参数a, b, c, d 是绝对值不超过10 的实数,最多保留小数点后两位。参数theta 是0~359 之间的整数。

输出格式

  对于每个点,输出一行,即变换后的坐标。对于每个平面,输出一行,即变换后平面方程的参数a, b, c 和d。输出应保证 a 2 + b 2 + c 2 = 1 a^2+b^2+c^2=1 a2+b2+c2=1,但如果有多种表示方法,任意一种均可。输出应保留两位小数。本题允许一定的浮点误差。

分析

  先说几个坑点:1、题面交代输入用4个整数a, b, c, d描述一个平面,实际数据会有浮点数,所以应该用double接收,否则WA;2、题面说输出接受0.05的误差,可能是相对误差(即5%),因为生成测试数据后Udebug输出的结果和lrj仓库代码输出的结果相差挺大的,所以果断全程double来算就行了。

  三个仿射变换矩阵中,平移、缩放矩阵好写,难的是旋转矩阵,具体可参考三维仿射变换矩阵。
  绕原点且单位法向量为 ( a , b , c ) (a,b,c) (a,b,c)的轴旋转的变换矩阵为:
[ cos ⁡ θ + a 2 ( 1 − cos ⁡ θ ) a b ( 1 − cos ⁡ θ ) − c sin ⁡ θ a c ( 1 − cos ⁡ θ ) + b sin ⁡ θ 0 a b ( 1 − cos ⁡ θ ) + c sin ⁡ θ cos ⁡ θ + b 2 ( 1 − cos ⁡ θ ) b c ( 1 − c o s θ ) − a sin ⁡ θ 0 a c ( 1 − cos ⁡ θ ) − b sin ⁡ θ b c ( 1 − cos ⁡ θ ) + a sin ⁡ θ cos ⁡ θ + c 2 ( 1 − cos ⁡ θ ) 0 0 0 0 1 ] \begin{bmatrix} \cos\theta + a^2(1-\cos\theta) & ab(1-\cos\theta)-c\sin\theta & ac(1-\cos\theta)+b\sin\theta & 0 \\ ab(1-\cos\theta)+c\sin\theta & \cos\theta+b^2(1-\cos\theta) & bc(1-cos\theta)-a\sin\theta & 0 \\ ac(1-\cos\theta)-b\sin\theta & bc(1-\cos\theta)+a\sin\theta & \cos\theta+c^2(1-\cos\theta) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} cosθ+a2(1cosθ)ab(1cosθ)+csinθac(1cosθ)bsinθ0ab(1cosθ)csinθcosθ+b2(1cosθ)bc(1cosθ)+asinθ0ac(1cosθ)+bsinθbc(1cosθ)asinθcosθ+c2(1cosθ)00001
  《训练指南》建议用三点式求解平面的变换结果,那么需要解决如下问题:已知平面方程,如何让找出平面上不共线的三个点?具体可参考平面的四种方程及一些应用。
  已知平面的一般式方程 a x + b y + c z + d = 0 \bm{ax+by+cz+d=0} ax+by+cz+d=0,由于 a , b , c 不全为 0 \bm{a,b,c}不全为0 a,b,c不全为0,则:
   a ≠ 0 \bm{a \ne 0} a=0时,点 ( − d a , 0 , 0 ) , ( − c + d a , 0 , 1 ) , ( − b + d a , 1 , 0 ) \bm{(-\frac{d}{a},0,0),(-\frac{c+d}{a},0,1),(-\frac{b+d}{a},1,0)} (ad,0,0),(ac+d,0,1),(ab+d,1,0)在平面上且三点不共线;
   b ≠ 0 \bm{b \ne 0} b=0时,点 ( 0 , − d b , 0 ) , ( 0 , − c + d b , 1 ) , ( 1 , − a + d b , 0 ) \bm{(0,-\frac{d}{b},0),(0,-\frac{c+d}{b},1),(1,-\frac{a+d}{b},0)} (0,bd,0),(0,bc+d,1),(1,ba+d,0)在平面上且三点不共线;
   c ≠ 0 \bm{c \ne 0} c=0时,点 ( 0 , 0 , − d c ) , ( 0 , 1 , − b + d c ) , ( 1 , 0 , − a + d c ) \bm{(0,0, -\frac{d}{c}),(0,1,-\frac{b+d}{c}),(1,0,-\frac{a+d}{c})} (0,0,cd),(0,1,cb+d),(1,0,ca+d)在平面上且三点不共线。
  编程时推荐选择 a , b , c \bm{a,b,c} a,b,c中绝对值最大那个来构造点。

AC 代码

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

#define N 50010
double pl[N][4], p[N][3], l[3][4], r[4][4], v[3][4], e = M_PI/180;

double mul(const double (&r)[4], const double *v3) {
    return r[0]*v3[0] + r[1]*v3[1] + r[2]*v3[2] +  + r[3];
}

void load_trans(double a, double b, double c) {
    l[0][0] = 1.; l[0][1] = 0.; l[0][2] = 0.; l[0][3] = a;
    l[1][0] = 0.; l[1][1] = 1.; l[1][2] = 0.; l[1][3] = b;
    l[2][0] = 0.; l[2][1] = 0.; l[2][2] = 1.; l[2][3] = c;
}

void load_rot(double a, double b, double c, double theta) {
    double si = sin(theta), co = cos(theta), s = sqrt(a*a+b*b+c*c); a /= s; b /= s; c /= s;
    l[0][0] = co+a*a*(1-co); l[0][1] = a*b*(1-co)-c*si; l[0][2] = a*c*(1-co)+b*si; l[0][3] = 0.;
    l[1][0] = a*b*(1-co)+c*si; l[1][1] = co+b*b*(1-co); l[1][2] = b*c*(1-co)-a*si; l[1][3] = 0.;
    l[2][0] = a*c*(1-co)-b*si; l[2][1] = b*c*(1-co)+a*si; l[2][2] = co+c*c*(1-co); l[2][3] = 0.;
}

void load_scale(double a, double b, double c) {
    l[0][0] = a; l[0][1] = 0.; l[0][2] = 0.; l[0][3] = 0.;
    l[1][0] = 0.; l[1][1] = b; l[1][2] = 0.; l[1][3] = 0.;
    l[2][0] = 0.; l[2][1] = 0.; l[2][2] = c; l[2][3] = 0.;
}

void trans_plane(double a, double b, double c, double d) {
    double x = max(max(abs(a), abs(b)), abs(c));
    if (abs(a) == x) {
        v[0][0] = -d/a; v[0][1] = 0.; v[0][2] = .0;
        v[1][0] = -(c+d)/a; v[1][1] = 0.; v[1][2] = 1.;
        v[2][0] = -(b+d)/a; v[2][1] = 1.; v[2][2] = 0.;
    } else if (abs(b) == x) {
        v[0][0] = 0.; v[0][1] = -d/b;  v[0][2] = 0.;
        v[1][0] = 0.; v[1][1] = -(c+d)/b; v[1][2] = 1.;
        v[2][0] = 1.; v[2][1] = -(a+d)/b; v[2][2] = 0.;
    } else {
        v[0][0] = 0.; v[0][1] = 0.; v[0][2] = -d/c;
        v[1][0] = 0.; v[1][1] = 1.; v[1][2] = -(b+d)/c;
        v[2][0] = 1.; v[2][1] = 0.; v[2][2] = -(a+d)/c;
    }
    for (int i=0; i<3; ++i)
        l[i][0] = mul(r[0], v[i]), l[i][1] = mul(r[1], v[i]), l[i][2] = mul(r[2], v[i]);
    double x1 = l[1][0]-l[0][0], y1 = l[1][1]-l[0][1], z1 = l[1][2]-l[0][2],
        x2 = l[2][0]-l[0][0], y2 = l[2][1]-l[0][1], z2 = l[2][2]-l[0][2],
        e = y1*z2 - z1*y2, f = x2*z1 - x1*z2, g = x1*y2 - x2*y1, s = sqrt(e*e + f*f + g*g);
        e /= s; f /= s; g /= s;
    cout << e << ' ' << f << ' ' << g << ' ' << -(e*l[0][0] + f*l[0][1] + g*l[0][2]) << endl;
}

void solve() {
    int m, n, t; char s[10]; double a, b, c, d; cin >> n >> m >> t;
    for (int i=0; i<n; ++i) cin >> p[i][0] >> p[i][1] >> p[i][2];
    for (int i=0; i<m; ++i) cin >> pl[i][0] >> pl[i][1] >> pl[i][2] >> pl[i][3];
    for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) r[i][j] = i==j ? 1. : 0.;
    while (t--) {
        cin >> s >> a >> b >> c;
        if (s[0] == 'T') load_trans(a, b, c);
        else if (s[0] == 'R') cin >> d, load_rot(a, b, c, d*e);
        else load_scale(a, b, c);
        for (int i=0; i<3; ++i) for (int j=0; j<4; ++j)
            v[i][j] = l[i][0]*r[0][j] + l[i][1]*r[1][j] + l[i][2]*r[2][j] + l[i][3]*r[3][j];
        for (int i=0; i<3; ++i) for (int j=0; j<4; ++j) r[i][j] = v[i][j];
    }
    for (int i=0; i<n; ++i) cout << mul(r[0], p[i]) << ' ' << mul(r[1], p[i]) << ' ' << mul(r[2], p[i]) << endl;
    for (int i=0; i<m; ++i) trans_plane(pl[i][0], pl[i][1], pl[i][2], pl[i][3]);
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(2);
    solve();
    return 0;
}

相关文章:

  • c#客户端请求 Server-Sent Events
  • 音视频开发面试准备
  • Python组合数据类型(二)
  • Python字典,集合
  • Linux 网络:skb 数据管理
  • WEB实时推送消息的7种方式
  • 开发常用软件
  • C++设计模式-抽象工厂模式:从原理、适用场景、使用方法,常见问题和解决方案深度解析
  • Python 构建Flask网页端远程控制Windows系统功能
  • 基于Ollama平台部署的Qwen大模型实现聊天机器人
  • 计算机考研C语言
  • Docker搭建Redis哨兵模式【一主两从三哨兵】
  • 《TCP/IP网络编程》学习笔记 | Chapter 17:优于 select 的 epoll
  • 面试之《commonjs,requirejs和es6 Module的区别》
  • Photo Works在线图片编辑器:一键修复老照片,轻松焕新记忆
  • java-单列模式-final-枚举
  • 「 DelegateUI 」Ant-d 风格的 Qt Qml UI 套件
  • 瑞芯微RK3576(1)-硬件设计
  • 浙江大学:DeepSeek行业应用案例集(153页)(文末可下载PDF)
  • python-docx库的run._element.get_or_add_rPr()方法详解
  • 大规模空袭也门一日后,以军又对也门萨那机场发出撤离警告
  • 五一假期上海楼市延续向好态势,成交量同比增加36%
  • 董卓的前半生:边荒之地的工具人
  • 杨国荣︱《老子智慧八十一讲》及其他
  • 为什么有的人闻到烟味,会咳嗽、胸闷?别再伤害身边的人
  • 厦大历史系教授林汀水辞世,曾参编《中国历史地图集》