예제 #1
0
 Graph<int,int> grid(std::vector<int> args,int start=1)
 {
     if(args[0]<1 || args[1]<1)
         throw std::runtime_error("Not Possible : (m,n>0) not met ...");
     
     Graph<int,int> result;
     
     if(args[0]==1 && args[1]==1)
     {
         result.insertVertex(start);
         return result;
     }
     if(args[0]==1)
         return path({args[1]},start);
     if(args[1]==1)
         return path({args[0]},start);
     
     add_vertices(result,args[0]*args[1],start);
     
     for(int i=start;i<=start+args[0]*args[1]-1;i+=args[1])
         for(int j=i;j<=i+args[1]-2;++j)
             result.insertEdge(j,j+1,1);
         for(int i=start;i<=start+args[1]-1;++i)
             for(int j=i+args[1];j<=start+args[0]*args[1]-1;j+=args[1])
                 result.insertEdge(j-args[1],j,1);
             
             return result;
 }
예제 #2
0
파일: world.cpp 프로젝트: jdelgad/3de
void World::load(std::string const &filename) {
    std::ifstream map;
    map.open(filename, std::fstream::in);

    if (!map.is_open()) {
        throw std::runtime_error(filename + " does not exist");
    }

    std::string line;
    std::vector<Vertex> vertices;
    sectors.clear();
    while (std::getline(map, line)) {
        std::istringstream ss(line);
        std::string type;
        ss >> type;

        if (type == "vertex") {
            add_vertices(ss, vertices);
        } else if (type == "sector") {
            add_sector(ss, vertices);
        } else if (type == "player") {
            player = create_player(ss);
        } else {
            throw std::runtime_error("Could not load map. Invalid data format found in " + filename);
        }
    }

    map.close();
}
예제 #3
0
void Renderer::draw_line(const RenderListPtr &render_list, const Vec2 &from, const Vec2 &to, Color color)
{
	Vertex v[]
	{
		{ from.x, from.y, color },
		{ to.x,   to.y,   color }
	};

	add_vertices(render_list, v, D3DPT_LINELIST);
}
예제 #4
0
 Graph<int,int> k_ary_tree(std::vector<int> args,int start=1)   //args[0]=n, args[1]=k
 {
     Graph<int,int> result;
     add_vertices(result,args[0],start);
     
     for(int i=0;i<args[0];++i)
         for(int j=args[1]*i+1;j<=args[1]*i+args[1];++j)
             if(j+1<=args[0])
                 result.insertEdge(i+1,j+1,1);
             
             return result;
 }
예제 #5
0
 Graph<int,int> path(std::vector<int> args, int start=1)
 {
     if(args[0]<1)
         throw std::runtime_error("Not Possible : (n>0) not met ...");
     
     Graph<int,int> result;
     add_vertices(result,args[0],start);
     for(int i=start;i<=start+args[0]-2;++i)
         result.insertEdge(i,i+1,1);
     
     return result;
 }
예제 #6
0
gl_sgraph::gl_sgraph(const gl_sframe& vertex_sframe,
                     const gl_sframe& edge_sframe,
                     const std::string& vid_field,
                     const std::string& src_field,
                     const std::string& dst_field) {
  instantiate_new();
  if (!vertex_sframe.empty()) {
    m_sgraph = add_vertices(vertex_sframe, vid_field).m_sgraph;
  }
  if (!edge_sframe.empty()) {
    m_sgraph = add_edges(edge_sframe, src_field, dst_field).m_sgraph;
  }
}
예제 #7
0
 Graph<int,int> complete_bipartite(std::vector<int> args,int start=1)
 {
     if(args[0]<1 || args[1]<1)
         throw std::runtime_error("Not Possible : (m,n>0) not met ...");
     
     Graph<int,int> result;
     add_vertices(result,args[1]+args[0],start);
     for(int i=start;i<=start+args[0]-1;++i)
         for(int j=start+args[0];j<=start+args[0]+args[1]-1;++j)
             result.insertEdge(i,j,1);
         
         return result;
 }
예제 #8
0
/**
 * \brief Removing vertices preserves the cell indexation
 */
TEST_F(CMap0Test, remove_vertex)
{
	add_vertices(NB_MAX);

	uint32 count_vertices = NB_MAX;
	for (Dart d: darts_)
		if (std::rand() % 3 == 1)
		{
			cmap_.remove_vertex(Vertex(d));
			--count_vertices;
		}

	EXPECT_EQ(cmap_.nb_cells<Vertex::ORBIT>(), count_vertices);
	EXPECT_TRUE(cmap_.check_map_integrity());
}
예제 #9
0
void Renderer::draw_filled_rect(const RenderListPtr &render_list, const Vec4 &rect, Color color)
{
	Vertex v[]
	{
		{ rect.x,          rect.y,          color },
		{ rect.x + rect.z, rect.y,          color },
		{ rect.x,          rect.y + rect.w, color },

		{ rect.x + rect.z, rect.y,          color },
		{ rect.x + rect.z, rect.y + rect.w, color },
		{ rect.x,          rect.y + rect.w, color }
	};

	add_vertices(render_list, v, D3DPT_TRIANGLELIST);
}
예제 #10
0
void RenderState::mousePressEvent(QMouseEvent *event) {
  if(event->button() == Qt::LeftButton) {
    this->mousedown_left = true; // set for dragging the left button
    add_vertices(); // this will only happen when the vertices are addable
    edit_vertices(); // this will only happen when vertices can be edit
    translate_vertices();
    emit this->update_frame();
  } else if(event->button() == Qt::RightButton) {
    this->mousedown_right = true;
    this->clicked_position = new QVector3D(this->current_position->x(),
                                           this->current_position->y(),
                                           this->current_position->z());
    this->mouse_right_clicked_x = this->mouse_x;
    this->mouse_right_clicked_y = this->mouse_y;
  }
}
예제 #11
0
 Graph<int,int> star_polygon(std::vector<int> args,int start=1)
 {
     if(!(args[1]>1 && args[0]>2*args[1]))
         throw std::runtime_error("Not Possible : (2<2q<p) not met ...");
     
     Graph<int,int> result;
     add_vertices(result,args[0],start);
     
     int end=start+args[0]-1;
     for(int i=start,j=start+args[1];i<=end;++i)
     {
         result.insertEdge(i,j,1);
         if(j==end)
             j=start;
         else
             j++;
     }
     
     return result;
 }
예제 #12
0
void Renderer::draw_circle(const RenderListPtr &render_list, const Vec2 &position, float radius, Color color /* = 0UL */)
{
	const int segments = 24;

	Vertex v[segments + 1];

	for (int i = 0; i <= segments; i++)
	{
		float theta = 2.f * D3DX_PI * static_cast<float>(i) / static_cast<float>(segments);

		v[i] = Vertex
		{
			position.x + radius * std::cos(theta),
			position.y + radius * std::sin(theta),
			color
		};
	}

	add_vertices(render_list, v, D3DPT_LINESTRIP);
}
예제 #13
0
파일: polyfill.c 프로젝트: johan/pike
static int polyfill_event(double xmin,
                          double xmax,
                          double yp,
                          double *buf,
                          struct line_list **pll,
                          int tog)
{
    struct line_list *c;
    struct line_list *ll=*pll;
    int mtog;

#ifdef POLYDEBUG
    fprintf(stderr," event %g,%g - %g,%g tog=%d\n",xmin,yp,xmax,yp+1.0,tog);
#endif

    /* toggle for lines ended at xmin,yp */
    c=ll;
    while (c)
    {
        if ( (c->above->y < yp) &&
                ( (c->xmax==xmin && c->yxmax==yp) ||
                  (c->xmin==xmin && c->yxmin==yp) ) )
        {
#ifdef POLYDEBUG
            fprintf(stderr,"    toggle for %g,%g - %g,%g [%g,%g - %g,%g]\n",
                    c->xmin,c->yxmin,c->xmax,c->yxmax,
                    c->above->x,c->above->y,c->below->x,c->below->y);
#endif
            tog=!tog;
        }
        c=c->next;
    }

#if 0
    /* sanity check */
    c=ll;
    while (c && c->next)
    {
        if (c->xmin > c->next->xmax ||
                ( c->xmin!=c->xmax &&
                  c->next->xmin!=c->next->xmax &&
                  c->xmax>=xmin &&
                  c->xmin<=xmin &&
                  c->next->xmax>=xmin &&
                  c->next->xmin<=xmin &&
                  (VY(c,xmin)>VY(c->next,xmin) ||
                   VY(c,xmax)>VY(c->next,xmax))) )
        {
            struct line_list *l1;
            /* resort */
#ifdef POLYDEBUG
            fprintf(stderr,"  !!! internal resort !!!\n");
            fprintf(stderr,"  on pair: %g,%g - %g,%g [%g,%g - %g,%g]\n           %g,%g - %g,%g [%g,%g - %g,%g]\n",
                    c->xmin,c->yxmin,c->xmax,c->yxmax,
                    c->above->x,c->above->y,c->below->x,c->below->y,
                    c->next->xmin,c->next->yxmin,c->next->xmax,c->next->yxmax,
                    c->next->above->x,c->next->above->y,
                    c->next->below->x,c->next->below->y);
#endif
            l1=NULL;
            add_vertices(&l1,ll,yp);

            while ((c=*pll))
            {
                *pll=c->next;
                free(c);
            }

            ll=*pll=l1;

            break;
        }
        c=c->next;
    }
#endif

    /* paint if needed */
    if (tog)
    {
#ifdef POLYDEBUG
        fprintf(stderr,"  fill %g..%g with 1.0\n",xmin,xmax);
#endif
        polyfill_row_add(buf,xmin,xmax,1.0);
    }

    /* loop over events */
    mtog=tog;
    c=ll;

    while (c)
    {
        if (c->xmin<=xmin && c->xmax>=xmax)
        {
            double y1 = VY(c,xmin);
#ifdef POLYDEBUG
            double y2 = VY(c,xmax);
            fprintf(stderr,"  use line %g,%g - %g,%g [%g,%g - %g,%g] : %g,%g - %g,%g = %+g\n",
                    c->xmin,c->yxmin,c->xmax,c->yxmax,
                    c->above->x,c->above->y,c->below->x,c->below->y,
                    xmin,y1,xmax,y2,(tog?-1.0:1.0)*((y1+y2)/2.0-yp));
#endif
            polyfill_slant_add(buf,xmin,xmax,
                               DO_NOT_WARN(tog?-1.0:1.0),
                               (yp+1)-y1,-c->dy);
            tog=!tog;
        }
        if (c->xmin>xmax) break; /* skip the rest */
        c=c->next;
    }


    return mtog;
}
예제 #14
0
파일: delaunay.cpp 프로젝트: omco/geode
// Retriangulate a cavity formed when a constraint edge is inserted, following Shewchuck and Brown.
// The cavity is defined by a counterclockwise list of vertices v[0] to v[m-1] as in Shewchuck and Brown, Figure 5.
static void cavity_delaunay(MutableTriangleTopology& parent_mesh, RawField<const EV,VertexId> X,
                            RawArray<const VertexId> cavity, Random& random) {
  // Since the algorithm generates meshes which may be inconsistent with the outer mesh, and the cavity
  // array may have duplicate vertices, we use a temporary mesh and then copy the triangles over when done.
  // In the temporary, vertices are indexed consecutively from 0 to m-1.
  const int m = cavity.size();
  assert(m >= 3);
  const auto mesh = new_<MutableTriangleTopology>();
  Field<Perturbed2,VertexId> Xc(m,uninit);
  for (const int i : range(m))
    Xc.flat[i] = Perturbed2(cavity[i].id,X[cavity[i]]);
  mesh->add_vertices(m);
  const auto xs = Xc.flat[0],
             xe = Xc.flat[m-1];

  // Set up data structures for prev, next, pi in the paper
  const Field<VertexId,VertexId> prev(m,uninit),
                                 next(m,uninit);
  for (int i=0;i<m-1;i++) {
    next.flat[i] = VertexId(i+1);
    prev.flat[i+1] = VertexId(i);
  }
  const Array<VertexId> pi_(m-2,uninit);
  for (int i=1;i<=m-2;i++)
    pi_[i-1] = VertexId(i);
  #define PI(i) pi_[(i)-1]

  // Randomly shuffle [1,m-2], subject to vertices closer to xs-xe than both their neighbors occurring later
  for (int i=m-2;i>=2;i--) {
    int j;
    for (;;) {
      j = random.uniform<int>(0,i)+1;
      const auto pj = PI(j);
      if (!(   segment_directions_oriented(xe,xs,Xc[pj],Xc[prev[pj]])
            && segment_directions_oriented(xe,xs,Xc[pj],Xc[next[pj]])))
        break;
    }
    swap(PI(i),PI(j));
    // Remove PI(i) from the list
    const auto pi = PI(i);
    next[prev[pi]] = next[pi];
    prev[next[pi]] = prev[pi];
  }

  // Add the first triangle
  mesh->add_face(vec(VertexId(0),PI(1),VertexId(m-1)));

  // Add remaining triangles, flipping to ensure Delaunay
  const Field<bool,VertexId> marked(m);
  Array<HalfedgeId> fan;
  bool used_chew = false;
  for (int i=2;i<m-1;i++) {
    const auto pi = PI(i);
    insert_cavity_vertex(mesh,Xc,marked,pi,next[pi],prev[pi]);
    if (marked[pi]) {
      used_chew = true;
      marked[pi] = false;
      // Retriangulate the fans of triangles that have all three vertices marked
      auto e = mesh->reverse(mesh->halfedge(pi));
      auto v = mesh->src(e);
      bool mv = marked[v];
      marked[v] = false;
      fan.clear();
      do {
        const auto h = mesh->prev(e);
        e = mesh->reverse(mesh->next(e));
        v = mesh->src(e);
        const bool mv2 = marked[v];
        marked[v] = false;
        if (mv) {
          if (mv2)
            fan.append(h);
          if (!mv2 || mesh->is_boundary(e)) {
            chew_fan(mesh,Xc,pi,fan,random);
            fan.clear();
          }
        }
        mv = mv2;
      } while (!mesh->is_boundary(e));
    }
  }
  #undef PI

  // If we ran Chew's algorithm, validate the output.  I haven't tested this
  // case enough to be confident of its correctness.
  if (used_chew)
    assert_delaunay("Failure in extreme special case.  If this triggers, please email [email protected]: ",
                    mesh,Xc,Tuple<>(),false,false);

  // Copy triangles from temporary mesh to real mesh
  for (const auto f : mesh->faces()) {
    const auto v = mesh->vertices(f);
    parent_mesh.add_face(vec(cavity[v.x.id],cavity[v.y.id],cavity[v.z.id]));
  }
}
예제 #15
0
파일: delaunay.cpp 프로젝트: omco/geode
// Delaunay retriangulate a triangle fan
static void chew_fan(MutableTriangleTopology& parent_mesh, RawField<const Perturbed2,VertexId> X,
                     const VertexId u, RawArray<HalfedgeId> fan, Random& random) {
  chew_fan_count_ += 1;
#ifndef NDEBUG
  for (const auto e : fan)
    assert(parent_mesh.opposite(e)==u);
  for (int i=0;i<fan.size()-1;i++)
    GEODE_ASSERT(parent_mesh.src(fan[i])==parent_mesh.dst(fan[i+1]));
#endif
  const int n = fan.size();
  if (n < 2)
    return;
  chew_fan_count_ += 1024*n;

  // Collect vertices
  const Field<VertexId,VertexId> vertices(n+2,uninit);
  vertices.flat[0] = u;
  vertices.flat[1] = parent_mesh.src(fan[n-1]);
  for (int i=0;i<n;i++)
    vertices.flat[i+2] = parent_mesh.dst(fan[n-1-i]);

  // Delete original vertices
  for (const auto e : fan)
    parent_mesh.erase(parent_mesh.face(e));

  // Make the vertices into a doubly linked list
  const Field<VertexId,VertexId> prev(n+2,uninit),
                                 next(n+2,uninit);
  prev.flat[0].id = n+1;
  next.flat[n+1].id = 0;
  for (int i=0;i<n+1;i++) {
    prev.flat[i+1].id = i;
    next.flat[i].id = i+1;
  }

  // Randomly shuffle the vertices, then pulling elements off the linked list in reverse order of our final shuffle.
  const Array<VertexId> pi(n+2,uninit);
  for (int i=0;i<n+2;i++)
    pi[i].id = i;
  random.shuffle(pi);
  for (int i=n+1;i>=0;i--) {
    const auto j = pi[i];
    prev[next[j]] = prev[j];
    next[prev[j]] = next[j];
  }

  // Make a new singleton mesh
  const auto mesh = new_<MutableTriangleTopology>();
  mesh->add_vertices(n+2);
  small_sort(pi[0],pi[1],pi[2]);
  mesh->add_face(vec(pi[0],pi[1],pi[2]));

  // Insert remaining vertices
  Array<HalfedgeId> work;
  for (int i=3;i<n+2;i++) {
    const auto j = pi[i];
    const auto f = mesh->add_face(vec(j,next[j],prev[j]));
    work.append(mesh->reverse(mesh->opposite(f,j)));
    while (work.size()) {
      auto e = work.pop();
      if (   !mesh->is_boundary(e)
          && incircle(X[vertices[mesh->src(e)]],
                      X[vertices[mesh->dst(e)]],
                      X[vertices[mesh->opposite(e)]],
                      X[vertices[mesh->opposite(mesh->reverse(e))]])) {
        work.append(mesh->reverse(mesh->next(e)));
        work.append(mesh->reverse(mesh->prev(e)));
        e = mesh->unsafe_flip_edge(e);
      }
    }
  }

  // Copy triangles back to parent
  for (const auto f : mesh->faces()) {
    const auto vs = mesh->vertices(f);
    parent_mesh.add_face(vec(vertices[vs.x],vertices[vs.y],vertices[vs.z]));
  }
}
예제 #16
0
파일: delaunay.cpp 프로젝트: omco/geode
// This routine assumes the sentinel points have already been added, and processes points in order
GEODE_NEVER_INLINE static Ref<MutableTriangleTopology> deterministic_exact_delaunay(RawField<const Perturbed2,VertexId> X, const bool validate) {

  const int n = X.size()-3;
  const auto mesh = new_<MutableTriangleTopology>();
  IntervalScope scope;

  // Initialize the mesh to a Delaunay triangle containing the sentinels at infinity.
  mesh->add_vertices(n+3);
  mesh->add_face(vec(VertexId(n+0),VertexId(n+1),VertexId(n+2)));
  if (self_check) {
    mesh->assert_consistent();
    assert_delaunay("self check 0: ",mesh,X);
  }

  // The randomized incremental construction algorithm uses the history of the triangles
  // as the acceleration structure.  Specifically, we maintain a BSP tree where the nodes
  // are edge tests (are we only the left or right of an edge) and the leaves are triangles.
  // There are two operations that modify this tree:
  //
  // 1. Split: A face is split into three by the insertion of an interior vertex.
  // 2. Flip: An edge is flipped, turning two triangles into two different triangles.
  //
  // The three starts out empty, since one triangle needs zero tests.
  Array<Node> bsp; // All BSP nodes including leaves
  bsp.preallocate(3*n); // The minimum number of possible BSP nodes
  Field<Vector<int,2>,FaceId> face_to_bsp; // Map from FaceId to up to two BSP leaf points (2*node+(right?0:1))
  face_to_bsp.flat.preallocate(2*n+1); // The exact maximum number of faces
  face_to_bsp.flat.append_assuming_enough_space(vec(0,-1)); // By the time we call set_links, node 0 will be valid
  if (self_check)
    check_bsp(*mesh,bsp,face_to_bsp,X);

  // Allocate a stack to simulate recursion when flipping non-Delaunay edges.
  // Invariant: if edge is on the stack, the other edges of face(edge) are Delaunay.
  // Since halfedge ids change during edge flips in a corner mesh, we store half edges as directed vertex pairs.
  Array<Tuple<HalfedgeId,Vector<VertexId,2>>> stack;
  stack.preallocate(8);

  // Insert all vertices into the mesh in random order, maintaining the Delaunay property
  for (const auto i : range(n)) {
    const VertexId v(i);
    check_interrupts();

    // Search through the BSP tree to find the containing triangle
    const auto f0 = bsp_search(bsp,X,v);
    const auto vs = mesh->vertices(f0);

    // Split the face by inserting the new vertex and update the BSP tree accordingly.
    mesh->split_face(f0,v);
    const auto e0 = mesh->halfedge(v),
               e1 = mesh->left(e0),
               e2 = mesh->right(e0);
    assert(mesh->dst(e0)==vs.x);
    const auto f1 = mesh->face(e1),
               f2 = mesh->face(e2);
    const int base = bsp.extend(3,uninit);
    set_links(bsp,face_to_bsp[f0],base);
    bsp[base+0] = Node(vec(v,vs.x),base+2,base+1);
    bsp[base+1] = Node(vec(v,vs.y),~f0.id,~f1.id);
    bsp[base+2] = Node(vec(v,vs.z),~f1.id,~f2.id);
    face_to_bsp[f0] = vec(2*(base+1)+0,-1);
    face_to_bsp.flat.append_assuming_enough_space(vec(2*(base+1)+1,2*(base+2)+0));
    face_to_bsp.flat.append_assuming_enough_space(vec(2*(base+2)+1,-1));
    if (self_check) {
      mesh->assert_consistent();
      check_bsp(*mesh,bsp,face_to_bsp,X);
    }

    // Fix all non-Delaunay edges
    stack.copy(vec(tuple(mesh->next(e0),vec(vs.x,vs.y)),
                   tuple(mesh->next(e1),vec(vs.y,vs.z)),
                   tuple(mesh->next(e2),vec(vs.z,vs.x))));
    if (self_check)
      assert_delaunay("self check 1: ",mesh,X,Tuple<>(),true);
    while (stack.size()) {
      const auto evs = stack.pop();
      auto e = mesh->vertices(evs.x)==evs.y ? evs.x : mesh->halfedge(evs.y.x,evs.y.y);
      if (e.valid() && !is_delaunay(*mesh,X,e)) {
        // Our mesh is linearly embedded in the plane, so edge flips are always safe
        assert(mesh->is_flip_safe(e));
        e = mesh->unsafe_flip_edge(e);
        GEODE_ASSERT(is_delaunay(*mesh,X,e));
        // Update the BSP tree for the triangle flip
        const auto f0 = mesh->face(e),
                   f1 = mesh->face(mesh->reverse(e));
        const int node = bsp.append(Node(mesh->vertices(e),~f1.id,~f0.id));
        set_links(bsp,face_to_bsp[f0],node);
        set_links(bsp,face_to_bsp[f1],node);
        face_to_bsp[f0] = vec(2*node+1,-1);
        face_to_bsp[f1] = vec(2*node+0,-1);
        if (self_check) {
          mesh->assert_consistent();
          check_bsp(*mesh,bsp,face_to_bsp,X);
        }
        // Recurse to successor edges to e
        const auto e0 = mesh->next(e),
                   e1 = mesh->prev(mesh->reverse(e));
        stack.extend(vec(tuple(e0,mesh->vertices(e0)),
                         tuple(e1,mesh->vertices(e1))));
        if (self_check)
          assert_delaunay("self check 2: ",mesh,X,Tuple<>(),true);
      }
    }
    if (self_check) {
      mesh->assert_consistent();
      assert_delaunay("self check 3: ",mesh,X);
    }
  }

  // Remove sentinels
  for (int i=0;i<3;i++)
    mesh->erase_last_vertex_with_reordering();

  // If desired, check that the final mesh is Delaunay
  if (validate)
    assert_delaunay("delaunay validate: ",mesh,X);

  // Return the mesh with the sentinels removed
  return mesh;
}
예제 #17
0
/**
 * \brief Adding vertices preserves the cell indexation
 */
TEST_F(CMap0Test, add_vertex)
{
	add_vertices(NB_MAX);
	EXPECT_EQ(cmap_.nb_cells<Vertex::ORBIT>(), NB_MAX);
	EXPECT_TRUE(cmap_.check_map_integrity());
}
예제 #18
0
/**
 * \brief The random generated maps used in the tests are sound.
 */
TEST_F(CMap0Test, random_map_generators)
{
	add_vertices(NB_MAX);
	EXPECT_TRUE(cmap_.check_map_integrity());
}
예제 #19
0
파일: polyfill.c 프로젝트: johan/pike
static void polyfill_some(struct image *img,
                          struct vertex *v,
                          double *buf)
{
    struct line_list *ll=NULL;
    int y=0;
    double ixmax = (double)img->xsize;
    struct vertex *to_add=v,*to_loose=v;
    /* beat row for row */

    if (y+1.0+1e-10<v->y)
        y = DOUBLE_TO_INT(v->y);

    while (y<img->ysize && (to_loose||to_add) )
    {
        double yp = y;
        struct line_list *c;
        double xmin, xmax;
        rgb_group *d;
        int tog=0;
        int i;

#ifdef POLYDEBUG
        fprintf(stderr,"\nline %d..%d\n",y,y+1);
#endif

        /* update values for current lines */
        c=ll;
        while (c)
        {
            c->xmin=line_xmin(c,yp,&c->yxmin);
            c->xmax=line_xmax(c,yp,&c->yxmax);
            c=c->next;
        }

        /* add any new vertices */
        while (to_add && to_add->y<yp+1.0)
        {
            struct vertex *vx=to_add;
            to_add=to_add->next;
            add_vertices(&ll,vx->below,yp);
        }

#ifdef POLYDEBUG
        c=ll;
        while (c)
        {
            fprintf(stderr,"  line %g,%g - %g,%g [%g,%g - %g,%g]\n",
                    c->xmin,c->yxmin,c->xmax,c->yxmax,
                    c->above->x,c->above->y,c->below->x,c->below->y);
            c=c->next;
        }

#endif

        if (!ll)
        {
            y++;
            continue;
        }

        /* begin with zeros */
        for (i=0; i<img->xsize; i++) buf[i]=0.0;

        /* sanity check */
        c=ll;
        while (c && c->next)
        {
            if (c->xmin > c->next->xmax ||
                    c->xmax > c->next->xmin ||
                    ( c->xmin!=c->xmax &&
                      c->next->xmin!=c->next->xmax &&
                      c->next->xmax>=c->xmin &&
                      c->next->xmin<=c->xmin &&
                      VY(c,c->xmin)>VY(c->next,c->xmin)))
            {
                struct line_list *l1;
                /* resort */
#ifdef POLYDEBUG
                fprintf(stderr,"  !!! resort !!!\n");
#endif
                l1=NULL;
                add_vertices(&l1,ll,yp);

                while ((c=ll))
                {
                    ll=c->next;
                    free(c);
                }

                ll=l1;

                break;
            }
            c=c->next;
        }

        /* find first horisintal event */
        xmin=ll->xmin;
        c=ll;
        while (c)
        {
            if (c->xmin<xmin) xmin=c->xmin;
            c=c->next;
        }

        /* loop through all horisontal events */
        while (xmin<ixmax)
        {
            xmax=1e10;
            c=ll;
            while (c)
            {
                /* each line has two events: beginning and end */
                if (c->xmin<xmax && c->xmin>xmin) xmax=c->xmin;
                if (c->xmax<xmax && c->xmax>xmin) xmax=c->xmax;
                c=c->next;
            }
            if (xmax==1e10) break; /* no more events */

            if (xmax>ixmax) xmax=ixmax;
            tog=polyfill_event(xmin,xmax,yp,buf,&ll,tog);

            /* shift to get next event */
            xmin = xmax;
            xmax = DO_NOT_WARN(xmin - 1.0);
        }


        /* remove any old vertices */
        while (to_loose!=to_add && to_loose->y<yp+1.0-1e-10)
        {
            struct vertex *vx=to_loose;
            to_loose=to_loose->next;
            sub_vertices(&ll,vx,yp);
        }

        /* write this row */
        d=img->img+img->xsize*y;
        if(THIS->alpha)
        {
            for (i=0; i<img->xsize; i++)
            {
#ifdef POLYDEBUG
                fprintf(stderr,"%3.2f ",buf[i]);
#endif

#define apply_alpha(x,y,alpha) \
   ((unsigned char)((y*(255L-(alpha))+x*(alpha))/255L))

                d->r = apply_alpha( d->r,
                                    DOUBLE_TO_COLORTYPE((d->r*(1.0-buf[i]))+
                                                        (img->rgb.r*buf[i])),
                                    THIS->alpha );
                d->g = apply_alpha( d->g,
                                    DOUBLE_TO_COLORTYPE((d->g*(1.0-buf[i]))+
                                                        (img->rgb.g*buf[i])),
                                    THIS->alpha );
                d->b = apply_alpha( d->b,
                                    DOUBLE_TO_COLORTYPE((d->b*(1.0-buf[i]))+
                                                        (img->rgb.b*buf[i])),
                                    THIS->alpha );
                d++;
            }
#ifdef POLYDEBUG
            fprintf(stderr,"\n");
#endif
        }
        else {
            for (i=0; i<img->xsize; i++)
            {
#ifdef POLYDEBUG
                fprintf(stderr,"%3.2f ",buf[i]);
#endif
                d->r = DOUBLE_TO_COLORTYPE((d->r*(1.0-buf[i]))+(img->rgb.r*buf[i]));
                d->g = DOUBLE_TO_COLORTYPE((d->g*(1.0-buf[i]))+(img->rgb.g*buf[i]));
                d->b = DOUBLE_TO_COLORTYPE((d->b*(1.0-buf[i]))+(img->rgb.b*buf[i]));
                d++;
            }
#ifdef POLYDEBUG
            fprintf(stderr,"\n");
#endif
        }

        y++;
    }
    while (ll)
    {
        struct line_list *c;
        ll=(c=ll)->next;
        free(c);
    }
}