複素数
回転と平行移動のみなので,複素数による実装が簡単.
実装
右目と左目を区別することに注意. よって,平行移動と回転は一意に定まる.
操作後の点たちを,平行移動 -> 回転 の順で求める. 平行移動を忘れずに.
使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"
//---------------------------------------------------------------------------------------------------
// Complex numbers
template<typename T>
class ComNum{
public:
ComNum<T> inv (){ // return inverse of (*this)
T x,y; x = (*this).re(), y = (*this).im();
if(x==0 && y==0) return ComNum(); // fail
T n2 = x*x + y*y;
return ComNum(x/n2, -y/n2);
}
T norm2(){
}
T norm(){
return sqrt(norm2());
}
ComNum<T> operator - (ComNum<T> b){ return (*this) + (b*(-1)); }
ComNum<T> operator * (ComNum<T> b){
T x,y,z,w;
x = (*this).re(), y = (*this).im();
z = b.re(), w = b.im();
return ComNum<T>(x*z-y*w, x*w+y*z);
}
ComNum<T> operator / (ComNum<T> b){ return (*this)*b.inv(); }
};
template<typename T> ComNum<T> operator * (T sc, ComNum<T> b){ return b*sc; }
template<typename T> ComNum<T> operator / (T sc, ComNum<T> b){ return b/sc; }
template<typename T> bool operator == (ComNum<T> a, ComNum<T> b){
return a.re() == b.re() && a.im() == b.im();
}
template<typename T> bool operator != (ComNum<T> a, ComNum<T> b){
return !(a == b);
}
//---------------------------------------------------------------------------------------------------
int main() {
using C = ComNum<double>;
ll n;
cin >> n;
rep(i,2) {
double x,y;
cin >> x >> y;
eye[i] = C(x,y);
}
rep(i,n){
ll s,t; cin >> s >> t;
b.push_back(ComNum<double>(s,t));
}
C ce = (eye[0] + eye[1])/2.0;
double e = (eye[1] - ce).norm();
C th = (eye[1] - ce) / C(e, 0.0);
rep(i,n){
C z = (b[i] - ce)/th;
printf("%.10lf %.10lf\n", z.re(), z.im());
}
return 0;
}
*1:*this).re()*sc, (*this).im()*sc); }
ComNum<T> operator / (T sc){ return (*this)*(1/sc); } // Remark : 1/sc if T is integer case
ComNum<T> operator + (ComNum<T> b){ return ComNum<T>((*this).re()+b.re(), (*this).im()+b.im(