#include <iostream>
#include <algorithm>
#include <cmath>
#include <complex>
#include <vector>
using namespace std;

typedef complex<double> P;

const double eps = 1e-8;
const double pi = acos(-1);

bool equals(double a, double b) { return abs(a - b) < eps; }

namespace std {
  bool operator < (const P &a, const P b) {
    return ( a.real() != b.real()
             ? a.real() < b.real() : a.imag() < b.imag() );
  }
}

struct L : public vector<P> {
  L(P a, P b) {
    push_back(a), push_back(b);
  }
};

struct C {
  P o;
  double r;
  C() {}
  C(P o, double r) : o(o), r(r) {}
};

double dot  (P a, P b) { return a.real()*b.real() + a.imag()*b.imag(); }
double cross(P a, P b) { return a.real()*b.imag() - a.imag()*b.real(); }

double getDistanceLP(P s1, P s2, P p) {
  return fabs(cross(s2 - s1, p - s1)/abs(s2 - s1));
}

int isIntersect(C a, C b) {
  double x = a.o.real() - b.o.real();
  double y = a.o.imag() - b.o.imag();
  double s = a.r + b.r;
  double d = x*x + y*y;
  s *= s;
  if(equals(d, s)) return 1;
  if(d > s) return 0;
  double r = abs(a.r - b.r);
  r *= r;
  if(equals(d, r)) return -1;
  if(d > r) return 2;
  return -2;
}

vector<P> getCrossP(C c1, C c2) {
  vector<P> v;
  int cp = isIntersect(c1,c2);
  if(cp == 0 || cp == -2) return v;
  
  double ll = norm(c1.o - c2.o);
  double A = ( c1.r * c1.r - c2.r * c2.r + ll ) / ( 2.0 * ll );
  P base = c2.o - c1.o;

  if(abs(cp) == 1) {
    v.push_back(c1.o + A*base);
  } else {
    P n(-base.imag(), base.real());
    n /= abs(n);
    double h = sqrt(c1.r * c1.r - A*A*ll);
    v.push_back(c1.o + A*base + h*n);
    v.push_back(c1.o + A*base - h*n);
  }
  return v;
}

vector<L> getLine(C a, C b) {
  vector<L> res;
  bool swapped = false;
  if (a.r > b.r) {
    swap(a, b);
    swapped = true;
  }
  int c = isIntersect(a, b);

  if (c == -2) {
    // there are no lines
  } else if (abs(c) == 1) {
    P cp = getCrossP(a, b)[0];
    P base = b.o - a.o;
    P n(-base.imag(), base.real());
    res.push_back(L(cp, cp + n));
  } else {
    {
      if (a.r == b.r) {
        P base = b.o - a.o;
        P n(-base.imag(), base.real());
        n /= abs(n);
        res.push_back(L(a.o + n * a.r, b.o + n * a.r));
        res.push_back(L(a.o - n * a.r, b.o - n * a.r));
      } else {
        double h = b.r - a.r;
        double x = sqrt(norm(a.o - b.o) - h * h);
        vector<P> ps = getCrossP(C(b.o, h), C(a.o, x));
        for (int i = 0; i < ps.size(); ++i) {
          P n = ps[i] - b.o;
          n /= abs(n);
          res.push_back(L(a.o + n * a.r, ps[i] + n * a.r));
        }
      }
    }
    {
      double h = b.r + a.r;
      double x = sqrt(norm(a.o - b.o) - h * h);
      vector<P> ps = getCrossP(C(b.o, h), C(a.o, x));
      for (int i = 0; i < ps.size(); ++i) {
        P n = b.o - ps[i];
        n /= abs(n);
        res.push_back(L(a.o + n * a.r, ps[i] + n * a.r));
      }
    }
  }

  if (swapped) {
    for (int i = 0; i < res.size(); ++i) {
      swap(res[i][0], res[i][1]);
    }
  }
  return res;
}

// aoj 2201
int main(void) {
  int N;
  vector<P> p;
  vector<double> r, m;
  while(cin >> N && N) {
    p.resize(N);
    r.resize(N);
    m.resize(N);
    for(int i = 0; i < N; ++i) {
      cin >> p[i].real() >> p[i].imag() >> r[i] >> m[i];
    }
    if(N == 1) {
      cout << 1 << endl;
      continue;
    }
    vector<L> ls;
    for(int i = 0; i < N; ++i) {
      for(int j = i+1; j < N; ++j) {
        vector<L> tmp;
        tmp = getLine(C(p[i], r[i]), C(p[j], r[j]));
        for(int k = 0; k < tmp.size(); ++k) ls.push_back(tmp[k]);
        tmp = getLine(C(p[i], r[i]+m[i]), C(p[j], r[j]));
        for(int k = 0; k < tmp.size(); ++k) ls.push_back(tmp[k]);
        tmp = getLine(C(p[i], r[i]), C(p[j], r[j]+m[j]));
        for(int k = 0; k < tmp.size(); ++k) ls.push_back(tmp[k]);
        tmp = getLine(C(p[i], r[i]+m[i]), C(p[j], r[j]+m[j]));
        for(int k = 0; k < tmp.size(); ++k) ls.push_back(tmp[k]);
      }
    }

    int res = 0;
    for(int k = 0; k < ls.size(); ++k) {
      int cnt = 0;
      for(int i = 0; i < N; ++i) {
        double d = getDistanceLP(ls[k][0], ls[k][1], p[i]);
        if((equals(d, r[i]) || d > r[i]) &&
           (equals(d-r[i], m[i]) || d-r[i] < m[i])) ++cnt;
      }
      res = max(res, cnt);
    }
    cout << res << endl;
  }
  return 0;
}

Measured memory_bytes: 3724