C++の基礎(第1回) 練習問題解答例
第1回練習問題の解答例

問1

三次元ベクトルクラスVec3を作れ。加減(+, -)とスカラー倍(*, /)を定義せよ。

問2

2つのVec3を受けとり、内積を返す関数double dot(const Vec3& v1, const Vec3& v2)を作れ。

問3

Vec3クラスに長さを求めるメンバ関数double length() const を追加せよ。

解答例

#include <cstdio>
#include <cmath>
class Vec3 {
    public:
        double x;
        double y;
        double z;

        Vec3() {
            x = y = z = 0;
        };
        Vec3(double _x, double _y, double _z) {
            x = _x;
            y = _y;
            z = _z;
        };

        double length() const {
            return std::sqrt(x*x + y*y + z*z);
        };
};

Vec3 operator+(const Vec3& v1, const Vec3& v2) {
    return Vec3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
Vec3 operator-(const Vec3& v1, const Vec3& v2) {
    return Vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}

Vec3 operator*(double k, const Vec3& v) {
    return Vec3(k * v.x, k * v.y, k * v.z);
}
Vec3 operator*(const Vec3& v, double k) {
    return k*v;
}

Vec3 operator/(double k, const Vec3& v) {
    return Vec3(k / v.x, k / v.y, k / v.z);
}
Vec3 operator/(const Vec3& v, double k) {
    return Vec3(v.x / k, v.y / k, v.z / k);
}

double dot(const Vec3& v1, const Vec3& v2) {
    return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}


int main() {
    Vec3 v1(1, 1, 1);
    Vec3 v2(2, 2, 2);
    Vec3 v3 = v1 + v2;
    printf("%f\n", dot(v1, v2));
    printf("%f\n", v3.length());
    return 0;
}

問4

作成したVec3クラスを使って、球を表すクラスSphereを作れ。球は中心座標(Vec3)と半径(double)をメンバ変数として持つとする。

解答例

class Sphere {
    public:
        Vec3 center; //中心座標
        double radius; //半径

        Sphere(const Vec3& center, double radius) : center(center), radius(radius) {};
};

問5

作成したVec3クラスを使って、直線を表すクラスRayを作れ。直線は始点(Vec3)と方向(Vec3)をメンバ変数として持つとする。

解答例

class Ray {
    public:
        Vec3 origin; //始点
        Vec3 direction; //方向

        Ray(const Vec3& origin, const Vec3& direction) : origin(origin), direction(direction) {};
};

問6(レイトレ)

SphereにRayとの衝突計算を行うメンバ関数bool intersect(const Ray& ray) constを作れ。衝突したらtrueを、衝突しない場合はfalseを返す。直線の方向を前側としたときに、直線の始点より後側で衝突した場合もfalseとする。

解答例

class Sphere {
    public:
        Vec3 center;
        double radius;

        Sphere(const Vec3& center, double radius) : center(center), radius(radius) {};

        bool intersect(const Ray& ray) const {
            double d_norm = ray.direction.length();
            double oc_norm = (ray.origin - center).length();

            double a = d_norm*d_norm;
            double b = 2*dot(ray.direction, ray.origin - center);
            double c = oc_norm*oc_norm - radius*radius;
            double D = b*b - 4*a*c;
            if(D < 0) return false;

            //解の候補
            double t1 = (-b - std::sqrt(D))/(2*a);
            double t2 = (-b + std::sqrt(D))/(2*a);

            //衝突距離
            double t = t1;
            if(t < 0) {
                t = t2;
                if(t < 0) return false;
            }

            return true;
        }
};