/*
13:20 - 15:39 :: first time
15:39 - 17:13 Finished
 */

#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
#include<cassert>
#include<climits>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define EPS (1e-8)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1
#define ONLINE_BACK 2
#define ONLINE_FRONT -2 
#define ON_SEGMENT 0
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define MAX_N 5000
#define MAX_E 5000

using namespace std;

// Library - template - begin
class Point{
public:
  double x,y;

  Point(double x=-IINF,double y=-IINF):x(x),y(y){}

  Point operator + (Point p) { return Point(x+p.x,y+p.y); }
  Point operator - (Point p) { return Point(x-p.x,y-p.y); }
  Point operator * (double a){ return Point(x*a,y*a); }
  Point operator / (double a){ return Point(x/a,y/a); }
  Point operator * (Point a) { return Point(x*a.x-y*a.y,x*a.y+y*a.x); }

  bool operator < (const Point& p)const{
    return !equals(x,p.x)?x<p.x:y<p.y;
  }
  bool operator == (const Point& p)const{
    return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
  }
};

struct Segment{
  Point p1,p2;
  Segment(Point p1=Point(),Point p2=Point()):p1(p1),p2(p2){}
  bool operator == (const Segment& p)const{
    return p.p1 == p1 && p.p2 == p2;
  }
};

typedef Segment Line;
typedef vector<Point> Polygon;

double dot(Point a,Point b){ return a.x*b.x+a.y*b.y; }
double cross(Point a,Point b){ return a.x*b.y-a.y*b.x; }
double norm(Point a){ return a.x*a.x+a.y*a.y; }
double abs(Point a){ return sqrt(norm(a)); }
// Library - template - end 13:32

// Library - CCW - begin
int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}
// Library - CCW - end 13:34

// Library - intersect - begin

bool intersectSS(Line s,Line t){
  return ccw(s.p1,s.p2,t.p1) * ccw(s.p1,s.p2,t.p2) <= 0 && ccw(t.p1,t.p2,s.p1) * ccw(t.p1,t.p2,s.p2) <= 0;
}

bool intersectSP(Line s,Point p){
  return abs(s.p1-p) + abs(s.p2-p) - abs(s.p2-s.p1) < EPS;
}

Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    assert(vec[1] == vec[2]);
    return vec[1];
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}
// Library - intersect - end 13:47


// Library - segmentArrangement - begin

struct Edge{
  int from,to,rev;
  double cost;
  Edge(int from=IINF,int to=IINF,int rev=IINF,double cost=IINF):from(from),to(to),rev(rev),cost(cost){}
  bool operator < (const Edge& a)const {
    return cost < a.cost;
  }
};

vector<vector<Edge>> segmentArrangement(vector<Segment> vs,vector<Point> &ps){

  rep(i,vs.size())REP(j,i+1,vs.size())if(intersectSS(vs[i],vs[j])){
    ps.push_back(Point(crosspoint(vs[i],vs[j])));
  }

  sort(ps.begin(),ps.end());

  ps.erase(unique(ps.begin(),ps.end()),ps.end());

  vector<vector<Edge> > ret(ps.size());

  for(int i=0;i<vs.size();i++){
    vector<pair<double,int> > list;
    rep(j,ps.size())if(intersectSP(vs[i],ps[j])){
      list.push_back(pair<double,int>(norm(vs[i].p1-ps[j]),j));
    }
    sort(list.begin(),list.end());
    for(int j=0;j+1<list.size();++j){
      int from = list[j].second, to = list[j+1].second;
      double cost = abs(ps[from]-ps[to]);
      ret[from].push_back(Edge(from,to,ret[to].size(),cost));
      ret[to].push_back(Edge(to,from,ret[from].size()-1,cost));
    }
  }
  return ret;
}
// Library - segmentArrangement - end 13:42

// Library - all - 27

// Library - add 15:29 -> 15:39

// Library - inPolygon - begin

double cross3p(Point p,Point q,Point r){
  return (r.x-q.x)*(p.y-q.y)-(r.y-q.y)*(p.x-q.x);
}

bool collinear(Point p,Point q,Point r){
  return fabs(cross3p(p,q,r)) < EPS;
}

bool ccwtest(Point p,Point q,Point r){
  return cross3p(p,p,r) > 0;
}

bool onSegment(Point p,Point q,Point r){
  return collinear(p,q,r) && equals(sqrt(pow(p.x-r.x,2)+pow(p.y-r.y,2)) +
				    sqrt(pow(r.x-q.x,2)+pow(r.y-q.y,2)),
				    sqrt(pow(p.x-q.x,2)+pow(p.y-q.y,2)));
}

double angle(Point a,Point b,Point c){
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx+uy*vy)/sqrt((ux*ux+uy*uy)*(vx*vx+vy*vy)));
}

bool inPolygon(Polygon poly,Point p){
  if((int)poly.size() == 0)return false;
  rep(i,poly.size())
    if(onSegment(poly[i],poly[(i+1)%(int)poly.size()],p))return true;
  double sum = 0;
  rep(i,(int)poly.size()){
    if(cross3p(p,poly[i],poly[(i+1)%(int)poly.size()]) < 0)
      sum -= angle(p,poly[i],poly[(i+1)%(int)poly.size()]);
    else 
      sum += angle(p,poly[i],poly[(i+1)%(int)poly.size()]);
  }
  return (fabs(sum-2*M_PI) < EPS || fabs(sum + 2*M_PI) < EPS);
}

// Library - inPolygon - end 15:39

int n;
vector<Segment> segs;
vector<vector<Edge>> G;
vector<Point> ps;
bool used[MAX_N][MAX_E][2];
//used[ノード番号i][iのエッジj][方向k] := ノードiのエッジjの方向kを使ったか？
// k->false : 出て行く方向　
// k->true  : 入ってくる方向

bool cmp(const Edge& e1,const Edge& e2){
  Point from = ps[e1.from];
  assert(e1.from == e2.from);
  Point to1 = ps[e1.to];
  Point to2 = ps[e2.to];
  double rad1 = atan2(to1.y-from.y,to1.x-from.x);
  double rad2 = atan2(to2.y-from.y,to2.x-from.x);
  return rad1 <= rad2;
}

//node => 今いるノード、 edge => 今いるノードから出る辺で、次に進む先を示す
void getCycle(int node,int edge,vector<Point>& cycle){
  if(used[node][edge][false])return;

  int from = G[node][edge].from;
  int to = G[node][edge].to;
  int rev = G[node][edge].rev;
  cycle.push_back(ps[to]);
  assert(!used[node][edge][false] && !used[to][rev][true]);
  used[node][edge][false] = used[to][rev][true] = true;

  int next = (rev+1) % (int)G[to].size();
  getCycle(to,next,cycle);

}

void compute(){

  ps.clear();
  G.clear();
  G = segmentArrangement(segs,ps);

  int limit_e = 0;

  rep(i,G.size()){
    sort(G[i].begin(),G[i].end(),cmp);
    limit_e = max(limit_e,(int)G[i].size());
  }

  rep(i,G.size()){
    rep(j,G[i].size()){
      int to = G[i][j].to;
      rep(k,G[to].size()){
	if(G[i][j].from == G[to][k].to && 
	   G[i][j].to   == G[to][k].from){
	  G[i][j].rev = k;
	  G[to][k].rev = j;
	}
      }
    }
  }

  rep(i,G.size())rep(j,limit_e)rep(k,2)used[i][j][k] = false;

  rep(node,G.size()){
    if(G[node].empty())continue;
    int from = G[node][0].from;
    assert(from == G[node][0].from);

    rep(edge,G[node].size()){
      int to = G[node][edge].to;
      rep(dir,2){
	if(used[node][edge][dir])continue;
	vector<Point> cycle;
	int start_node,start_edge;
	if(dir == false){
	  cycle.push_back(ps[from]);
	  start_node = from, start_edge = edge;
	}
	else{
	  cycle.push_back(ps[to]);
	  start_node = to, start_edge = G[node][edge].rev;
	}

	getCycle(start_node,start_edge,cycle);
	int pos = IINF;
	rep(i,ps.size()){
	  if(ps[i] == cycle[cycle.size()-1]){
	    pos = i;
	    break;
	  }
	}

	assert(cycle.size() >= 3);
	if(inPolygon(cycle,Point(0,0))){
	  cout << "yes" << endl;
	  return;
	}
      }
    }
  }

  cout << "no" << endl;

}

int main(){

  while(cin >> n,n){
    segs.clear();
    segs.resize(n);
    for(Segment& seg : segs)cin >> seg.p1.x >> seg.p1.y >> seg.p2.x >> seg.p2.y;
    compute();
  }
  return 0;
}

Measured memory_bytes: 48336