// last update 2012/12/15

#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; }

bool equals(P a, P b) {
  return equals(a.real(), b.real()) && equals(a.imag(), b.real());
}

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 norm(P a) { return a.real()*a.real() + a.imag() * a.imag(); }
double abs (P a) { return sqrt(norm(a)); }
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(); }

bool isOrthogonal(P a, P b) { return equals(dot(a, b), 0.0); }
bool isParallel  (P a, P b) { return equals(cross(a, b), 0.0); }

P project(P s1, P s2, P p) {
  P base = s2 - s1;
  double t = dot(p - s1, base)/norm(base);
  return s1 + base*t;
}

P reflect(P s1, P s2, P p) { return p + (project(s1, s2, p) - p)*2.0; }

P getRotateP(P p, double rad, P o = P(0, 0)) {
  P q = p - o;
  return o + P(q.real()*cos(rad) - q.imag()*sin(rad),
	   q.real()*sin(rad) + q.imag()*cos(rad));
}

namespace CCW {
  enum { COUNTER_CLOCKWISE = 1, CLOCKWISE = -1,
	 ONLINE_BACK = 2, ONLINE_FRONT = -2,
	 ONSEGMENT = 0 };
}

int ccw(P p0, P a, P b) {
  a -= p0;
  b -= p0;
  if(cross(a, b) > eps) return CCW::COUNTER_CLOCKWISE;
  if(cross(a, b) < -eps) return CCW::CLOCKWISE;
  if(dot(a, b) < -eps) return CCW::ONLINE_BACK;
  if(norm(b)-norm(a) > eps) return CCW::ONLINE_FRONT;
  return CCW::ONSEGMENT;
}

// 
bool isIntersect(P a1, P a2, P b1, P b2) {
  return ( ccw(a1, a2, b1) * ccw(a1, a2, b2) <= 0 &&
	   ccw(b1, b2, a1) * ccw(b1, b2, a2) <= 0 );
}

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

double getDistanceSP(P s1, P s2, P p) {
  if(dot(s2 - s1, p - s1) < 0.0) return abs(p - s1);
  if(dot(s1 - s2, p - s2) < 0.0) return abs(p - s2);
  return getDistanceLP(s1, s2, p);
}

double getDistance(P a1, P a2, P b1, P b2) {
  if(isIntersect(a1,a2,b1,b2)) return 0.0;
  return min(min(getDistanceSP(a1,a2,b1), getDistanceSP(a1,a2,b2)),
             min(getDistanceSP(b1,b2,a1), getDistanceSP(b1,b2,a2)));
}

// 
int isIntersect(P s1, P s2, C c) {
  double d = getDistanceLP(s1, s2, c.o);
  if(equals(d, c.r)) return 1;
  else if(d < c.r) return 2;
  else return 0;
}

// 
//  0 : 
//  1 : 1
//  2 : 2
// -1 : 
// -2 : 
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;
}

// 
P getCrossP(P a1, P a2, P b1, P b2) {
  P a = a2 - a1;
  P b = b2 - b1;
  // cross 
  return a1 + a * cross(b, b1 - a1)/cross(b, a);
}

// 
vector<P> getCrossP(P s1, P s2, C c) {
  vector<P> v;
  P p = project(s1, s2, c.o);
  if(isIntersect(s1, s2, c) == 1) {
    v.push_back(p);
  } else {
    double h = abs(p-c.o);
    double d = sqrt(c.r*c.r - h*h);
    P base = s2 - s1;
    v.push_back(p + d*base/abs(base));
    v.push_back(p - d*base/abs(base));
  }
  return v;
}

// 
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;
}


// 2(0 <= rad <= PI)
double getAngle(P a, P b) {
  return acos(dot(a, b)/(abs(a)*abs(b)));
}

// (1, 0)(-PI <= rad <= PI)
double getAngle(P a) {
  return atan2(a.imag(), a.real());
}

// 2r
C getC(P a1, P a2, P b1, P b2, double r) {
  P a = a2 - a1;
  P b = b2 - b1;
  if(cross(a, b) < 0) swap(a, b);
  P p = getCrossP(a1, a2, b1, b2);
  double rad = getAngle(a, b);
  double alpha = getAngle(a);
  double d = r/sin(rad/2.0);
  C res;
  res.r = r;
  res.o = p + d * P(cos(alpha + rad/2.0), sin(alpha + rad/2.0));
  return res;
}

// 3
double heron(double a, double b, double c) {
  double s = (a+b+c)/2.0;
  return sqrt(s*(s-a)*(s-b)*(s-c));
}

// 
double getArea(vector<P> &G) {
  int n = G.size();
  double S = 0;
  for(int i = 0; i < n; ++i) {
    S += cross(G[i], G[(i+1)%n]);
  }
  return S/2.0;
}

// 
double getIncircleR(P p1, P p2, P p3) {
  double a = abs(p1 - p2);
  double b = abs(p2 - p3);
  double c = abs(p3 - p1);
  return heron(a,b,c)*2.0/(a+b+c);
}

vector<P> convex_hull(vector<P> ps) {
  int n = ps.size(), k = 0;
  sort(ps.begin(), ps.end());
  vector<P> ch(2*n);
  for(int i = 0; i < n; ch[k++] = ps[i++])
    while(k >= 2 && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
  for(int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--])
    while(k >= t && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
  ch.resize(k-1);
  return ch;
}

vector<P> convex_cut(vector<P> ps, P p1, P p2, int dir = CCW::CLOCKWISE) {
  vector<P> v;
  for(int i = 0; i < ps.size(); ++i) {
    P a = ps[i];
    P b = ps[(i+1)%ps.size()];
    if(ccw(p1, p2, a) != dir) v.push_back(a);
    if(ccw(p1, p2, a)*ccw(p1, p2, b) == -1)
      v.push_back(getCrossP(a, b, p1, p2));
  }
  return v;
}

// 
vector<L> getTangent(C a, C b) {
  if(a.r > b.r) swap(a,b);
  vector<L> res;
  double d = abs(b.o - a.o);
  double th;
  P v, n;
  int t = isIntersect(a, b);

  if(equals(a.o.real(), b.o.real()) && 
     equals(a.o.imag(), b.o.imag()) && 
     equals(a.r, b.r)) return res;
  if(t == -2) return res;

  if(t == 0 || t == 1 || t == 2) {
    th = asin((b.r - a.r)/d);

    v = getRotateP(b.o, th, a.o) - a.o;
    n = P(-v.imag(), v.real());
    n /= abs(n);
    res.push_back(L(a.o+n*a.r, b.o+n*b.r));
    
    v = getRotateP(b.o, -th, a.o) - a.o;
    n = P(v.imag(), -v.real());
    n /= abs(n);
    res.push_back(L(a.o+n*a.r, b.o+n*b.r));
  }

  if(t == 0) {
    th = asin((b.r + a.r)/d);

    v = getRotateP(b.o, th, a.o) - a.o;
    n = P(-v.imag(), v.real());
    n /= abs(n);
    res.push_back(L(a.o-n*a.r, b.o+n*b.r));
    
    v = getRotateP(b.o, -th, a.o) - a.o;
    n = P(v.imag(), -v.real());
    n /= abs(n);
    res.push_back(L(a.o-n*a.r, b.o+n*b.r));
  }

  if(t == 1) {
    n = b.o - a.o;
    n /= abs(n);
    v = P(-n.imag(), n.real());
    res.push_back(L(a.o + n*a.r, a.o + n*a.r + v));
  }

  if(t == -1) {
    n = a.o - b.o;
    n /= abs(n);
    v = P(-n.imag(), n.real());
    res.push_back(L(a.o + n*a.r, a.o + n*a.r + v));
  }

  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 = getTangent(C(p[i], r[i]), C(p[j], r[j]));
	for(int k = 0; k < tmp.size(); ++k) ls.push_back(tmp[k]);
	tmp = getTangent(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 = getTangent(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 = getTangent(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: 3780