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; }
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(); }
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); }
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; }
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; }
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; } }
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; }
/** * \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()); }
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); }
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; } }
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; }
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); }
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; }
// 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])); } }
// 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])); } }
// 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; }
/** * \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()); }
/** * \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()); }
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); } }