#include <bits/stdc++.h>
using namespace std;
array<array<double, 3>, 3> Zero() {
  array<array<double, 3>, 3> res;
  for (auto& row : res) fill(row.begin(), row.end(), 0.0);
  return res;
}
array<array<double, 3>, 3> One() {
  array<array<double, 3>, 3> res = Zero();
  for (int i = 0; i < 3; ++i) res[i][i] = 1.0;
  return res;
}
array<array<double, 3>, 3> Mult(const array<array<double, 3>, 3>& f,
                                const array<array<double, 3>, 3>& s) {
  array<array<double, 3>, 3> res = Zero();
  for (int i = 0; i < 3; ++i)
    for (int j = 0; j < 3; ++j)
      for (int k = 0; k < 3; ++k) res[i][k] += f[i][j] * s[j][k];
  return res;
}
array<double, 3> Mult(const array<array<double, 3>, 3>& f,
                      const array<double, 3>& s) {
  array<double, 3> res;
  fill(res.begin(), res.end(), 0);
  for (int i = 0; i < 3; ++i)
    for (int j = 0; j < 3; ++j) res[i] += f[i][j] * s[j];
  return res;
}
void Print(const array<double, 3>& p) {
  printf("%.10f %.10f\n", (double)p[0], (double)p[1]);
}
const int MAXN = 300010;
int n, m;
array<double, 3> in[MAXN];
array<array<double, 3>, 3> matr[MAXN];
array<array<double, 3>, 3> Translate(double dx, double dy) {
  return array<array<double, 3>, 3>({array<double, 3>({1, 0, dx}),
                                     array<double, 3>({0, 1, dy}),
                                     array<double, 3>({0, 0, 1})});
}
array<array<double, 3>, 3> Rotate(double ang) {
  double sina = sin(ang);
  double cosa = cos(ang);
  return array<array<double, 3>, 3>({array<double, 3>({cosa, sina, 0}),
                                     array<double, 3>({-sina, cosa, 0}),
                                     array<double, 3>({0, 0, 1})});
}
struct Tree {
  int lo, hi;
  Tree *left, *right;
  array<array<double, 3>, 3> po;
  Tree(int _lo = 0, int _hi = 0, Tree* _left = NULL, Tree* _right = NULL) {
    lo = _lo, hi = _hi;
    left = _left, right = _right;
  }
  static Tree* Build(int lo, int hi) {
    Tree* root = new Tree(lo, hi);
    if (lo == hi)
      root->po = Translate(1.0, 0.0);
    else {
      root->left = Build(lo, (lo + hi) >> 1);
      root->right = Build(((lo + hi) >> 1) + 1, hi);
      root->po = Mult(root->left->po, root->right->po);
    }
    return root;
  }
  void Update(int vr, const array<array<double, 3>, 3>& with) {
    if (lo == hi)
      po = Mult(with, po);
    else {
      if (vr <= ((lo + hi) >> 1))
        left->Update(vr, with);
      else
        right->Update(vr, with);
      po = Mult(left->po, right->po);
    }
  }
};
Tree* root;
array<double, 3> Oxy({0.0, 0.0, 1.0});
array<array<double, 3>, 3> Do1(int i, int len) {
  array<double, 3> dlt = Mult(matr[i], Oxy);
  double mod = sqrt(((dlt[0]) * (dlt[0])) + ((dlt[1]) * (dlt[1])));
  double po = len / mod;
  return Translate(dlt[0] * po, dlt[1] * po);
}
array<array<double, 3>, 3> Do2(double ang) { return Rotate(ang); }
int main() {
  scanf("%d%d", &n, &m);
  root = Tree::Build(0, n - 1);
  for (int i = 0; i < n; ++i) matr[i] = Translate(1.0, 0.0);
  for (int i = 0; i < m; ++i) {
    int x, y, z;
    scanf("%d%d%d", &x, &y, &z);
    if (x == 1) {
      auto po = Do1(y - 1, z);
      root->Update(y - 1, po);
      matr[y - 1] = Mult(po, matr[y - 1]);
    } else {
      auto po = Do2(z / 360.0 * 2 * 3.14159265358979323846);
      root->Update(y - 1, po);
      matr[y - 1] = Mult(po, matr[y - 1]);
    }
    Print(Mult(root->po, Oxy));
  }
  return 0;
}
