#include "bits/stdc++.h"
#define REP(i, n) for (int i = 0; i < (n); i++)
#define FOR(i, m, n) for (int i = (m); i < (n); i++)
#define ALL(x) x.begin(), x.end()
using namespace std;
typedef complex<double> Point;
#define ALL(x) x.begin(), x.end()
//幾何 Geometry
const double EPS = 1e-8;
const double PI = acos(-1);
const bool DEBUG = false;
typedef complex<double> point;
istream &operator>>(istream &is, point &p) {
    double a, b;
    is >> a >> b;
    p = point(a, b);
    return is;
}
point operator*(const point &p, const double &d) { return point(real(p) * d, imag(p) * d); }
namespace std {
bool operator<(const point &a, const point &b) { return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b); }
}  // namespace std

//直線or線分
struct Line : public vector<point> {
    Line(const point &a, const point &b) {
        push_back(a);
        push_back(b);
    }
};
typedef vector<Line> Lines;

double cross(const point &a, const point &b) { return real(a) * imag(b) - imag(a) * real(b); }
double dot(const point &a, const point &b) { return real(a) * real(b) + imag(a) * imag(b); }
int ccw(point a, point b, point c) {
    b = b - a;
    c = c - a;
    if (cross(b, c) > EPS) return +1;   // counter clockwise
    if (cross(b, c) < -EPS) return -1;  // clockwise
    if (dot(b, c) < -EPS) return +2;    // c--a--b on line
    if (norm(b) < norm(c)) return -2;   // a--b--c on line
    return 0;
}
point direction(const point &p) {  //同じ向きの単位ベクトル
    return p / abs(p);
}
point orthogonal(const point &p) {  //法線ベクトル
    return point(-imag(p), real(p));
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
    return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS ||  // non-parallel
           abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS;    // same line
}
bool intersectLS(const Line &l, const Line &s) {
    return cross(l[1] - l[0], s[0] - l[0]) *  // s[0] is left of l
               cross(l[1] - l[0], s[1] - l[0]) <
           EPS;  // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) { return abs(cross(l[1] - p, l[0] - p)) < EPS; }
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
    if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS) return false;
    return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;  // triangle inequality
}

bool intersectSP(
    const Line &s,
    const point &p) {  // verified on 2020/04/03
                       // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;  // triangle inequality
}
bool isOnSegment(const Line &s, const Line &t) {
    if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))
        return true;
    else
        return false;
}
bool isSamePoint(const point &p1, const point &p2) { return abs(p1 - p2) < EPS; }
bool connectSS(const Line &s, const Line &t) {
    REP(i, 2)
    REP(j, 2) {
        if (s[i] == t[j]) return true;
    }
    return false;
}
bool intersectSS(const Line &s, const Line &t) {
    return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 && ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}
//端点が線分上に乗っている場合はfalseにする
bool intersectSS_strict(const Line &s, const Line &t) {
    if (isOnSegment(s, t)) return false;
    return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 && ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

//距離,交点
//射影 直線lにpから下した垂線との交点
point projection(
    const Line &l,
    const point &p) {  // verified on 2020/04/03
                       // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
    return l[0] + (l[0] - l[1]) * t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) { return p + (projection(l, p) - p) * 2; }
double distancePP(const point &a, const point &b) { return sqrt(norm(a - b)); }
double distanceLP(const Line &l, const point &p) { return abs(p - projection(l, p)); }
double distanceLL(const Line &l, const Line &m) { return intersectLL(l, m) ? 0 : distanceLP(l, m[0]); }
double distanceLS(const Line &l, const Line &s) {
    if (intersectLS(l, s)) return 0;
    return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
    const point r = projection(s, p);
    if (intersectSP(s, r)) return abs(r - p);
    return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(
    const Line &s,
    const Line &t) {  // verified on 2020/04/03
                      // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    if (intersectSS(s, t)) return 0;
    return min({distanceSP(s, t[0]), distanceSP(s, t[1]), distanceSP(t, s[0]), distanceSP(t, s[1])});
}
point crosspoint(const Line &l, const Line &m) {
    double A = cross(l[1] - l[0], m[1] - m[0]);
    double B = cross(l[1] - l[0], l[1] - m[0]);
    if (abs(A) < EPS && abs(B) < EPS) return m[0];  // same line
    if (abs(A) < EPS) assert(false);                // Precondition not satisfied
    return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) { return abs(p1 - p2); }

//円
struct Circle {
    point c;
    double r;
    Circle(const point &c_, double r_) : c(c_), r(r_) {}
};
// 2円の交点
vector<point> crosspointsCC(const Circle &a, const Circle &b) {
    vector<point> ret;
    point v = b.c - a.c;
    double d = abs(v);

    if (d + EPS > a.r + b.r) return ret;
    if (d < abs(a.r - b.r) + EPS) return ret;

    double x = (a.r * a.r - b.r * b.r + d * d) / (2 * d);
    double y = sqrt(max(a.r * a.r - x * x, 0.0));
    point t1 = direction(v) * point(0, 1);
    point t2 = -t1;
    point p1 = a.c + direction(v) * x + t1 * y;
    point p2 = a.c + direction(v) * x + t2 * y;
    ret.push_back(p1);
    ret.push_back(p2);
    return ret;
}
//点と円の接線
vector<point> tanline(const Point &p, const Circle &c) {
    vector<point> ret;
    double d = norm(p - c.c);
    double l = d - c.r * c.r;
    if (l < -EPS) return ret;
    if (l <= 0.0) l = 0.0;
    point cq = (p - c.c) * (c.r * c.r / d);
    point qs = (p - c.c) * (c.r * sqrt(l) / d) * point(0, 1);
    point s1 = c.c + cq + qs, s2 = c.c + cq - qs;
    ret.push_back(s1);
    ret.push_back(s2);
}
// 2円の共通接線 verified on 2020/04/07
vector<Line> get_common_tangent(Circle a, Circle b) {
    vector<Line> ret;
    if (a.r < b.r) swap(a, b);
    point v = b.c - a.c;
    double d = abs(v);               //中心間距離
    if (d - abs(a.r - b.r) > EPS) {  //外接線2本
        if (abs(a.r - b.r) < EPS) {
            point dir = direction(v) * a.r * point(0, 1);
            ret.push_back(Line(a.c + dir, b.c + dir));
            ret.push_back(Line(a.c - dir, b.c - dir));
        } else {
            point p = a.c * -b.r + b.c * a.r;
            p = p * (1.0 / (a.r - b.r));
            vector<point> bs = tanline(p, a);
            vector<point> as = tanline(p, b);
            REP(i, min(as.size(), bs.size())) { ret.push_back(Line(bs[i], as[i])); }
        }
    } else if (d - abs(a.r - b.r) > -EPS) {  //外接線1本
        point p = v + direction(v) * b.r;    //接点
        ret.push_back(Line(p, p + direction(v) * point(0, 1)));
    }

    if (d - (a.r + b.r) > EPS) {  //内接線2本
        double D = sqrt(max(d * d - (a.r + b.r) * (a.r + b.r), 0.0));
        double x = D * a.r / (a.r + b.r);
        double theta = atan(x / a.r);
        point p1 = a.c + direction(v) * point(cos(theta), sin(theta)) * a.r;
        point p2 = a.c + direction(v) * point(cos(theta), -sin(theta)) * a.r;
        Line l1(p1, p1 + direction(v) * point(cos(theta), sin(theta)) * point(0, -1));
        Line l2(p2, p2 + direction(v) * point(cos(theta), -sin(theta)) * point(0, 1));
        ret.push_back(l1);
        ret.push_back(l2);
        assert(abs(distanceLP(l1, a.c) - a.r) < EPS);
        assert(abs(distanceLP(l1, b.c) - b.r) < EPS);
    } else if (d - (a.r + b.r) > -EPS) {
        point p1 = a.c + direction(v) * a.r;
        point p2 = p1 + v * point(0, 1);
        ret.push_back(Line(p1, p2));
    }
    return ret;
}

//凸包
vector<point> convex_hull(vector<point> ps) {
    int n = ps.size(), k = 0;
    sort(ps.begin(), ps.end());
    vector<point> ch(2 * n);
    for (int i = 0; i < n; ch[k++] = ps[i++])  // lower-hull
        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--])  // upper-hull
        while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
    ch.resize(k - 1);
    return ch;
}

// 2点を通る半径Rの円の中心
pair<point, point> get_circle_from_2points(point &p1, point &p2, double R) {
    double d = dist(p1, p2);
    double x1 = p1.real(), x2 = p2.real();
    double y1 = p1.imag(), y2 = p2.imag();
    if (p1.imag() == p2.imag()) {
        double x = (x1 + x2) / 2.0;
        double dy = sqrt(R - d * d / 4);
        return {{x, y1 + dy}, {x, y1 - dy}};
    } else {
        double m = (x1 - x2) / (y2 - y1);
        double t = sqrt(R * R - d * d / 4);
        double dx = sqrt((t * t) / (m * m + 1));
        double dy = sqrt(t * t - dx * dx);
        double gx = (x1 + x2) / 2;
        double gy = (y1 + y2) / 2;
        if (m > EPS) {
            return {{gx + dx, gy + dy}, {gx - dx, gy - dy}};
        } else {
            return {{gx + dx, gy - dy}, {gx - dx, gy + dy}};
        }
    }
}
//長方形
struct Square {
    double lx, ly, rx, ry;
    Square(double lx_, double ly_, double rx_, double ry_) : lx(lx_), ly(ly_), rx(rx_), ry(ry_){};
    bool include(point &p) {
        return p.real() + EPS >= lx && p.real() - EPS <= rx && p.imag() + EPS >= ly && p.imag() - EPS <= ry;
    }
};

struct Polygon : public vector<point> {
    // 0->OUT, 1->ON, 2->IN
    int contains(const point &p) {
        bool in = false;
        int N = this->size();
        for (int i = 0; i < N; i++) {
            point a = this->at(i) - p;
            point b = this->at((i + 1) % N) - p;
            if (imag(a) > imag(b)) {
                std::swap(a, b);
            }
            if (imag(a) <= 0 && 0 < imag(b))
                if (cross(a, b) < 0) in = !in;
            if (cross(a, b) == 0 && dot(a, b) <= 0) return 1;
        }
        return in ? 2 : 0;
    }
};

int count_jewels(const Line &l, const vector<Circle> &Cs, const vector<double> &ms) {
    int ret = 0;
    REP(i, Cs.size()) {
        Circle c = Cs[i];
        double m = ms[i];
        double d = distanceLP(l, c.c);
        if (c.r - EPS < d && d < c.r + m + EPS) ret++;
    }
    return ret;
}
void test() {
    Circle c1(point(20, 4), 3);
    Circle c2(point(-10, -10), 5);
    vector<Line> ls = get_common_tangent(c1, c2);
    for (auto l : ls) {
        cout << l[0] << " " << l[1] << endl;
        double d1 = distanceLP(l, c1.c);
        double d2 = distanceLP(l, c2.c);
        cout << d1 << " " << d2 << endl;
    }
}
void solve() {
    // test();
    int N;
    cin >> N;
    if (N == 0) exit(0);
    vector<Circle> Cs, outerCs;
    vector<double> ms;

    REP(i, N) {
        double x, y, r, m;
        cin >> x >> y >> r >> m;
        ms.push_back(m);
        point c(x, y);
        Cs.push_back(Circle(c, r));
        outerCs.push_back(Circle(c, r + m));
    }
    int ans = 1;
    //大円同士の共通接線をためす
    REP(i, N) REP(j, N) {
        if (i == j) continue;
        vector<Line> ls = get_common_tangent(outerCs[i], outerCs[j]);
        for (auto l : ls) {
            int res = count_jewels(l, Cs, ms);
            ans = max(ans, res);
        }
    }

    //円と大円の共通接線
    REP(i, N) REP(j, N) {
        if (i == j) continue;
        vector<Line> ls = get_common_tangent(Cs[i], outerCs[j]);
        for (auto l : ls) {
            int res = count_jewels(l, Cs, ms);
            ans = max(ans, res);
        }
    }

    //円と円の共通接線(一応)
    REP(i, N) REP(j, N) {
        if (i == j) continue;
        vector<Line> ls = get_common_tangent(Cs[i], Cs[j]);
        for (auto l : ls) {
            int res = count_jewels(l, Cs, ms);
            ans = max(ans, res);
        }
    }

    //大円同士の交点

    cout << ans << endl;
}

signed main() {
    while (true) solve();
}


Measured memory_bytes: 3844