Example #1
0
Py::Object
RendererAgg::draw_rectangle(const Py::Tuple & args) {
  _VERBOSE("RendererAgg::draw_rectangle");
  args.verify_length(6);
  theRasterizer->reset_clipping();
  Py::Object gcEdge( args[0] );
  Py::Object rgbFaceMaybeNone( args[1] );
  
  double l = Py::Float( args[2] ); 
  double b = Py::Float( args[3] ); 
  double w = Py::Float( args[4] ); 
  double h = Py::Float( args[5] ); 
  
  set_clip_rectangle(gcEdge);
  
  double lw = points_to_pixels ( gcEdge.getAttr("_linewidth") ) ;
  
  agg::path_storage path;
  
  b = height - (b+h);
  path.move_to(l, b+h);
  path.line_to(l+w, b+h);
  path.line_to(l+w, b);
  path.line_to(l, b);
  path.close_polygon();
  
  agg::rgba edgecolor = get_color(gcEdge);
  
  
  if (rgbFaceMaybeNone.ptr() != Py_None) {
    //fill the face
    Py::SeqBase<Py::Object> rgbFace = rgbFaceMaybeNone;
    agg::rgba facecolor = rgb_to_color(rgbFace, edgecolor.a);
    
    rendererAA->color(facecolor);
    theRasterizer->add_path(path);    
    agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
    
    
  }
  
  //now fill the edge
  agg::conv_stroke<agg::path_storage> stroke(path);
  stroke.width(lw);
  rendererAA->color(edgecolor);
  //self->theRasterizer->gamma(agg::gamma_power(gamma));
  theRasterizer->add_path(stroke);
  agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
  
  return Py::Object();
  
}
Example #2
0
double worksheet::row_height(row_t row) const
{
    static const auto DefaultRowHeight = 15.0;

    if (has_row_properties(row) && row_properties(row).height.is_set())
    {
        return row_properties(row).height.get();
    }
    else
    {
        return points_to_pixels(DefaultRowHeight, 96.0);
    }
}
Example #3
0
double worksheet::column_width(column_t column) const
{
    static const auto DefaultColumnWidth = 51.85;

    if (has_column_properties(column))
    {
        return column_properties(column).width.get();
    }
    else
    {
        return points_to_pixels(DefaultColumnWidth, 96.0);
    }
}
Example #4
0
Py::Object
RendererAgg::draw_ellipse(const Py::Tuple& args) {
  _VERBOSE("RendererAgg::draw_ellipse");
  
  args.verify_length(6);  
  Py::Object gcEdge = args[0];
  Py::Object rgbFaceMaybeNone = args[1];
  
  double x = Py::Float( args[2] ); 
  double y = Py::Float( args[3] ); 
  double w = Py::Float( args[4] ); 
  double h = Py::Float( args[5] ); 
  
  set_clip_rectangle(gcEdge);
  
  //last arg is num steps
  agg::ellipse path(x, height-y, w, h, 100); 
  agg::rgba edgecolor = get_color(gcEdge);  
  
  
  if (rgbFaceMaybeNone.ptr() != Py_None) {
    Py::SeqBase<Py::Object> rgbFace = rgbFaceMaybeNone;
    agg::rgba facecolor = rgb_to_color(rgbFace, edgecolor.a);
    theRenderer->color(facecolor);
    theRasterizer->add_path(path);    
    theRasterizer->render(*slineP8, *theRenderer);  
    
  }
  
  
  //now fill the edge
  
  double lw = points_to_pixels ( gcEdge.getAttr("_linewidth") ) ;
  
  agg::conv_stroke<agg::ellipse> stroke(path);
  stroke.width(lw);
  theRenderer->color(edgecolor);
  //self->theRasterizer->gamma(agg::gamma_power(gamma));
  theRasterizer->add_path(stroke);
  theRasterizer->render(*slineP8, *theRenderer);  
  
  return Py::Object();
  
}
Example #5
0
Py::Object
RendererAgg::draw_lines(const Py::Tuple& args) {
  
  theRasterizer->reset_clipping();
  _VERBOSE("RendererAgg::draw_lines");
  args.verify_length(3);  
  Py::Object gc = args[0];
  Py::SeqBase<Py::Object> x = args[1];  //todo: use numerix for efficiency
  Py::SeqBase<Py::Object> y = args[2];  //todo: use numerix for efficiency
  
  set_clip_rectangle(gc);
  size_t Nx = x.length();
  size_t Ny = y.length();
  
  if (Nx!=Ny) 
    throw Py::ValueError("x and y must be equal length sequences");
  
  
  if (Nx<2) 
    throw Py::ValueError("x and y must have length >= 2");
  
  
  agg::vcgen_stroke::line_cap_e cap = get_linecap(gc);
  agg::vcgen_stroke::line_join_e join = get_joinstyle(gc);
  
  
  double lw = points_to_pixels ( gc.getAttr("_linewidth") ) ;
  //std::cout << "agg lw " << lw << std::endl;
  agg::rgba color = get_color(gc);
  
  
  // process the dashes
  Py::Tuple dashes = get_dashes(gc);
  
  bool useDashes = dashes[0].ptr() != Py_None;
  double offset = 0;
  Py::SeqBase<Py::Object> dashSeq;
  
  if ( dashes[0].ptr() != Py_None ) { // use dashes
    //TODO: use offset
    offset = points_to_pixels_snapto(dashes[0]);
    dashSeq = dashes[1]; 
  };
  
  
  agg::path_storage path;
  
  int isaa = antialiased(gc);

  double heightd = double(height);
  if (Nx==2) { 
    // this is a little hack - len(2) lines are probably grid and
    // ticks so I'm going to snap to pixel
    //printf("snapto %d\n", Nx);
    double x0 = Py::Float(x[0]);
    double y0 = Py::Float(y[0]);
    double x1 = Py::Float(x[1]);
    double y1 = Py::Float(y[1]);
    
    if (x0==x1) {
      x0 = (int)x0 + 0.5;
      x1 = (int)x1 + 0.5;
    }

    if (y0==y1) {
      y0 = (int)y0 + 0.5;
      y1 = (int)y1 + 0.5;
    }

    y0 = heightd-y0;
    y1 = heightd-y1;

    path.move_to(x0, y0);
    path.line_to(x1, y1);
    
  }
  else {
    double thisX = Py::Float( x[0] );
    double thisY = Py::Float( y[0] );
    thisY = heightd - thisY; //flipy
    path.move_to(thisX, thisY);
    for (size_t i=1; i<Nx; ++i) {
      thisX = Py::Float( x[i] );
      thisY = Py::Float( y[i] );
      thisY = heightd - thisY;  //flipy
      //if ((i<10) || i>=19990)
      //std::cout << i << " " << Nx << " " << thisX << " " << thisY << std::endl;
      path.line_to(thisX, thisY);
    }
  }  
  
  //std::cout << width << " " << height << std::endl;
  if (! useDashes ) {
    
    agg::conv_stroke<agg::path_storage> stroke(path);
    stroke.line_cap(cap);
    stroke.line_join(join);
    stroke.width(lw);
    //freeze was here std::cout << "\t adding path!" << std::endl;         
    theRasterizer->add_path(stroke);
  }
  else {
    // set the dashes //TODO: scale for DPI
    
    size_t N = dashSeq.length();
    if (N%2 != 0  ) 
      throw Py::ValueError("dashes must be an even length sequence");     
    
    typedef agg::conv_dash<agg::path_storage> dash_t;
    dash_t dash(path);
    
    double on, off;
    
    for (size_t i=0; i<N/2; i+=1) {
      on = points_to_pixels_snapto(dashSeq[2*i]);
      off = points_to_pixels_snapto(dashSeq[2*i+1]);
      dash.add_dash(on, off);
    }
    agg::conv_stroke<dash_t> stroke(dash);
    stroke.line_cap(cap);
    stroke.line_join(join);
    stroke.width(lw);
    theRasterizer->add_path(stroke);
    
  }
  
  if ( isaa ) {
    rendererAA->color(color);    
    agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); 
  }
  else {
    rendererBin->color(color);     
    agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); 
  }
  
  return Py::Object();
  
}
Example #6
0
Py::Object
RendererAgg::draw_regpoly_collection(const Py::Tuple& args) {
  theRasterizer->reset_clipping();
  
  _VERBOSE("RendererAgg::draw_regpoly_collection");
  args.verify_length(9);  
  
  
  set_clip_from_bbox(args[0]);

  Py::SeqBase<Py::Object> offsets = args[1];  

  // this is throwing even though the instance is a Transformation!
  //if (!Transformation::check(args[2])) 
  // throw Py::TypeError("RendererAgg::draw_regpoly_collection(clipbox, offsets, transOffset, verts, ...) expected a Transformation instance for transOffset");
  
  Transformation* transOffset = static_cast<Transformation*>(args[2].ptr());


  transOffset->eval_scalars();

  Py::SeqBase<Py::Object> verts = args[3];  
  Py::SeqBase<Py::Object> sizes = args[4];  
  Py::SeqBase<Py::Object> facecolors = args[5];  
  Py::SeqBase<Py::Object> edgecolors = args[6];  
  Py::SeqBase<Py::Object> linewidths = args[7];  
  Py::SeqBase<Py::Object> antialiaseds = args[8];  

  size_t Noffsets = offsets.length();
  size_t Nverts = verts.length();
  size_t Nsizes = sizes.length();
  size_t Nface = facecolors.length();
  size_t Nedge = edgecolors.length();
  size_t Nlw = linewidths.length();
  size_t Naa = antialiaseds.length();
  
  double thisx, thisy;
  
  // dump the x.y vertices into a double array for faster access
  double xverts[Nverts];
  double yverts[Nverts];
  Py::Tuple xy;
  for (size_t i=0; i<Nverts; ++i) {
    xy = Py::Tuple(verts[i]);
    xverts[i] = Py::Float(xy[0]);
    yverts[i] = Py::Float(xy[1]);
  }
  
  std::pair<double, double> offsetPair;
  for (size_t i=0; i<Noffsets; ++i) {
    Py::Tuple pos = Py::Tuple(offsets[i]);
    double xo = Py::Float(pos[0]);
    double yo = Py::Float(pos[1]);
    offsetPair = transOffset->operator()(xo, yo);
    
    
    double scale = Py::Float(sizes[i%Nsizes]);
    
    
    agg::path_storage path;
    
    for (size_t j=0; j<Nverts; ++j) {
      thisx = scale*xverts[j] + offsetPair.first;
      thisy = scale*yverts[j] + offsetPair.second;
      thisy = height - thisy;
      if (j==0) path.move_to(thisx, thisy);
      else path.line_to(thisx, thisy);

      
    }
    path.close_polygon();
    int isaa = Py::Int(antialiaseds[i%Naa]);     
    // get the facecolor and render
    Py::Tuple rgba = Py::Tuple(facecolors[ i%Nface]);
    double r = Py::Float(rgba[0]);
    double g = Py::Float(rgba[1]);
    double b = Py::Float(rgba[2]);
    double a = Py::Float(rgba[3]);
    if (a>0) { //only render if alpha>0
      agg::rgba facecolor(r, g, b, a); 

      theRasterizer->add_path(path);          

      if (isaa) {
	rendererAA->color(facecolor);    
	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); 
      }
      else {
	rendererBin->color(facecolor);    
	agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); 
      }
    } //renderer face
    
    // get the edgecolor and render
    rgba = Py::Tuple(edgecolors[ i%Nedge]);
    r = Py::Float(rgba[0]);
    g = Py::Float(rgba[1]);
    b = Py::Float(rgba[2]);
    a = Py::Float(rgba[3]);
    if (a>0) { //only render if alpha>0
      agg::rgba edgecolor(r, g, b, a); 

      agg::conv_stroke<agg::path_storage> stroke(path);
      //stroke.line_cap(cap);
      //stroke.line_join(join);
      double lw = points_to_pixels ( Py::Float( linewidths[i%Nlw] ) );
      stroke.width(lw);
      theRasterizer->add_path(stroke);

      // render antialiased or not
      if ( isaa ) {
	rendererAA->color(edgecolor);    
	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); 
      }
      else {      
	rendererBin->color(edgecolor);    
	agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); 
      }
    } //rendered edge
    
  } // for every poly
  return Py::Object();
}
Example #7
0
Py::Object
RendererAgg::draw_poly_collection(const Py::Tuple& args) {
  theRasterizer->reset_clipping();
  
  _VERBOSE("RendererAgg::draw_poly_collection");

  args.verify_length(9);  
  

  Py::SeqBase<Py::Object> verts = args[0];    

  //todo: fix transformation check
  Transformation* transform = static_cast<Transformation*>(args[1].ptr());
  transform->eval_scalars();

  set_clip_from_bbox(args[2]);

  Py::SeqBase<Py::Object> facecolors = args[3];  
  Py::SeqBase<Py::Object> edgecolors = args[4];  
  Py::SeqBase<Py::Object> linewidths = args[5];  
  Py::SeqBase<Py::Object> antialiaseds = args[6];  

  
  Py::SeqBase<Py::Object> offsets;
  Transformation* transOffset = NULL;
  bool usingOffsets = args[7].ptr() != Py_None;
  if (usingOffsets) {
    offsets = args[7];  
    //todo: fix transformation check
    transOffset = static_cast<Transformation*>(args[8].ptr());
    transOffset->eval_scalars();
  }

  size_t Noffsets = offsets.length();
  size_t Nverts = verts.length();
  size_t Nface = facecolors.length();
  size_t Nedge = edgecolors.length();
  size_t Nlw = linewidths.length();
  size_t Naa = antialiaseds.length();

  size_t N = (Noffsets>Nverts) ? Noffsets : Nverts;
   
  std::pair<double, double> xyo, xy;
  Py::Tuple thisverts;
  for (size_t i=0; i<N; ++i) {

    thisverts = verts[i % Nverts];

    if (usingOffsets) {
      Py::Tuple pos = Py::Tuple(offsets[i]);
      double xo = Py::Float(pos[0]);
      double yo = Py::Float(pos[1]);
      xyo = transOffset->operator()(xo, yo);
    }

    size_t Nverts = thisverts.length();
    agg::path_storage path;
    
    Py::Tuple thisvert;

    
    // dump the verts to double arrays so we can do more efficient
    // look aheads and behinds when doing snapto pixels
    double xs[Nverts], ys[Nverts];    
    for (size_t j=0; j<Nverts; ++j) {
      thisvert = Py::Tuple(thisverts[j]);
      double x = Py::Float(thisvert[0]);
      double y = Py::Float(thisvert[1]);
      xy = transform->operator()(x, y);      

      if (usingOffsets) {
	xy.first  += xyo.first;
	xy.second += xyo.second;
      }

      xy.second = height - xy.second;
      xs[j] = xy.first;
      ys[j] = xy.second;

    }

    for (size_t j=0; j<Nverts; ++j) {

      double x = xs[j];
      double y = ys[j];

      if (j==0) {
	if (xs[j] == xs[Nverts-1]) x = (int)xs[j] + 0.5;
	if (ys[j] == ys[Nverts-1]) y = (int)ys[j] + 0.5;
      }
      else if (j==Nverts-1) {
	if (xs[j] == xs[0]) x = (int)xs[j] + 0.5;
	if (ys[j] == ys[0]) y = (int)ys[j] + 0.5;
      }

      if (j < Nverts-1) {
	if (xs[j] == xs[j+1]) x = (int)xs[j] + 0.5;
	if (ys[j] == ys[j+1]) y = (int)ys[j] + 0.5;
      }
      if (j>0) {
	if (xs[j] == xs[j-1]) x = (int)xs[j] + 0.5;
	if (ys[j] == ys[j-1]) y = (int)ys[j] + 0.5;
      }

      if (j==0) path.move_to(x,y);
      else path.line_to(x,y); 
    }

    path.close_polygon();
    int isaa = Py::Int(antialiaseds[i%Naa]);     
    // get the facecolor and render
    Py::Tuple rgba = Py::Tuple(facecolors[ i%Nface]);
    double r = Py::Float(rgba[0]);
    double g = Py::Float(rgba[1]);
    double b = Py::Float(rgba[2]);
    double a = Py::Float(rgba[3]);
    if (a>0) { //only render if alpha>0
      agg::rgba facecolor(r, g, b, a); 

      theRasterizer->add_path(path);          

      if (isaa) {
	rendererAA->color(facecolor);    
	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
      }
      else {
	rendererBin->color(facecolor);    
	agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
      }
    } //renderer face
    
    // get the edgecolor and render
    rgba = Py::Tuple(edgecolors[ i%Nedge]);
    r = Py::Float(rgba[0]);
    g = Py::Float(rgba[1]);
    b = Py::Float(rgba[2]);
    a = Py::Float(rgba[3]);

    if (a>0) { //only render if alpha>0
      agg::rgba edgecolor(r, g, b, a); 

      agg::conv_stroke<agg::path_storage> stroke(path);
      //stroke.line_cap(cap);
      //stroke.line_join(join);
      double lw = points_to_pixels ( Py::Float( linewidths[i%Nlw] ) );
      stroke.width(lw);
      theRasterizer->add_path(stroke);

      // render antialiased or not
      if ( isaa ) {
	rendererAA->color(edgecolor);    
	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); 
      }
      else {
	rendererBin->color(edgecolor);    
	agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); 
      }
    } //rendered edge
    
  } // for every poly
  return Py::Object();
}
Example #8
0
Py::Object
RendererAgg::draw_line_collection(const Py::Tuple& args) {
  theRasterizer->reset_clipping();
  
  _VERBOSE("RendererAgg::draw_line_collection");

  args.verify_length(8);  
  
  
  //segments, trans, clipbox, colors, linewidths, antialiaseds
  Py::SeqBase<Py::Object> segments = args[0];  


  /* this line is broken, mysteriously
  if (!Transformation::check(args[1])) 
    throw Py::TypeError("RendererAgg::draw_line_collection(segments, transform, ...) expected a Transformation instance for transform");
  
  */

  Transformation* transform = static_cast<Transformation*>(args[1].ptr());

  set_clip_from_bbox(args[2]);

  Py::SeqBase<Py::Object> colors = args[3];  
  Py::SeqBase<Py::Object> linewidths = args[4];  
  Py::SeqBase<Py::Object> antialiaseds = args[5];  

  bool usingOffsets = args[6].ptr()!=Py_None;
  Py::SeqBase<Py::Object> offsets;
  Transformation* transOffset=NULL;
  if  (usingOffsets) {
    offsets = Py::SeqBase<Py::Object>(args[6]);        
    transOffset = static_cast<Transformation*>(args[7].ptr());
  }

  size_t Nsegments = segments.length();
  size_t Nc = colors.length();
  size_t Nlw = linewidths.length();
  size_t Naa = antialiaseds.length();
  size_t Noffsets = 0;
  size_t N = Nsegments;

  if (usingOffsets) {
    Noffsets = offsets.length();
    if (Noffsets>Nsegments) N = Noffsets;
  }

  double xo(0.0), yo(0.0), thisx(0.0), thisy(0.0);
  std::pair<double, double> xy;  
  Py::Tuple xyo;
  Py::SeqBase<Py::Object> xys;
  for (size_t i=0; i<N; ++i) {
    if (usingOffsets) {
      xyo = Py::Tuple(offsets[i%Noffsets]);
      xo = Py::Float(xyo[0]);
      yo = Py::Float(xyo[1]);
      xy = transOffset->operator()(xo,yo);
      xo = xy.first;
      yo = xy.second;
    }

    xys = segments[i%Nsegments];
    size_t numtups = xys.length();
    if (numtups<2) continue;
      
    agg::path_storage path;

    for (size_t j=0; j<numtups; j++) {
      xyo = xys[j];
      thisx = Py::Float(xyo[0]);
      thisy = Py::Float(xyo[1]);
      xy = transform->operator()(thisx,thisy);
      thisx = xy.first;
      thisy = xy.second;

      if (usingOffsets) {
	thisx += xo;
	thisy += yo;
      }      
      if (j==0)  path.move_to(thisx, height-thisy);
      else       path.line_to(thisx, height-thisy);
    }

    agg::conv_stroke<agg::path_storage> stroke(path);
    //stroke.line_cap(cap);
    //stroke.line_join(join);
    double lw = points_to_pixels ( Py::Float( linewidths[i%Nlw] ) );
    
    stroke.width(lw);
    theRasterizer->add_path(stroke);

    // get the color and render
    Py::Tuple rgba = Py::Tuple(colors[ i%Nc]);
    double r = Py::Float(rgba[0]);
    double g = Py::Float(rgba[1]);
    double b = Py::Float(rgba[2]); 
    double a = Py::Float(rgba[3]);
    agg::rgba color(r, g, b, a); 

    // render antialiased or not
    int isaa = Py::Int(antialiaseds[i%Naa]);
    if ( isaa ) {
      rendererAA->color(color);    
      agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
    }
    else {
      rendererBin->color(color);    
      agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
    }
  } //for every segment
  return Py::Object();
}
Example #9
0
Py::Object
RendererAgg::draw_polygon(const Py::Tuple& args) {
  _VERBOSE("RendererAgg::draw_polygon");
  theRasterizer->reset_clipping();  
  args.verify_length(3);  

  Py::Object gcEdge( args[0] );
  Py::Object rgbFaceMaybeNone( args[1] );
  Py::SeqBase<Py::Object> points( args[2] );

  
  set_clip_rectangle(gcEdge);
  agg::vcgen_stroke::line_cap_e cap = get_linecap(gcEdge);
  agg::vcgen_stroke::line_join_e join = get_joinstyle(gcEdge);
  
  double lw = points_to_pixels ( gcEdge.getAttr("_linewidth") ) ;

  size_t Npoints = points.length();
  if (Npoints<=0)
    return Py::Object();


  // dump the x.y vertices into a double array for faster look ahread
  // and behind access
  double xs[Npoints];
  double ys[Npoints];
  Py::Tuple xy;
  for (size_t i=0; i<Npoints; ++i) {
    xy = Py::Tuple(points[i]);
    xs[i] = Py::Float(xy[0]);
    ys[i] = Py::Float(xy[1]);
    ys[i] = height - ys[i];

  }
  

  agg::path_storage path;  
  for (size_t j=0; j<Npoints; ++j) {

    double x = xs[j];
    double y = ys[j];
     
    if (j==0) path.move_to(x,y);
    else path.line_to(x,y); 
  }
  path.close_polygon();

  agg::rgba edgecolor = get_color(gcEdge);

  
  if (rgbFaceMaybeNone.ptr() != Py_None) {
    //fill the face
    Py::SeqBase<Py::Object> rgbFace = rgbFaceMaybeNone;
    agg::rgba facecolor = rgb_to_color(rgbFace, edgecolor.a);
    rendererAA->color(facecolor);
    theRasterizer->add_path(path);    
    agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
  }

  //now fill the edge
  agg::conv_stroke<agg::path_storage> stroke(path);
  stroke.width(lw);
  stroke.line_cap(cap);
  stroke.line_join(join);
  
  rendererAA->color(edgecolor);
  //self->theRasterizer->gamma(agg::gamma_power(gamma));
  theRasterizer->add_path(stroke);
  agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
  return Py::Object();
  
}
Example #10
0
Py::Object
RendererAgg::draw_line_collection(const Py::Tuple& args) {
  
  
  _VERBOSE("RendererAgg::draw_line_collection");
  args.verify_length(8);  
  
  
  //segments, trans, clipbox, colors, linewidths, antialiaseds
  Py::SeqBase<Py::Object> segments = args[0];  


  /* this line is broken, mysteriously
  if (!Transformation::check(args[1])) 
    throw Py::TypeError("RendererAgg::draw_line_collection(segments, transform, ...) expected a Transformation instance for transform");
  
  */

  Transformation* transform = static_cast<Transformation*>(args[1].ptr());

  set_clip_from_bbox(args[2]);

  Py::SeqBase<Py::Object> colors = args[3];  
  Py::SeqBase<Py::Object> linewidths = args[4];  
  Py::SeqBase<Py::Object> antialiaseds = args[5];  

  bool usingOffsets = args[6].ptr()!=Py_None;
  Py::SeqBase<Py::Object> offsets;
  Transformation* transOffset=NULL;
  if  (usingOffsets) {
    /* this line is broken, mysteriously
    if (!Transformation::check(args[7])) 
      throw Py::TypeError("RendererAgg::draw_line_collection expected a Transformation instance for transOffset");
    */
    offsets = Py::SeqBase<Py::Object>(args[6]);        
    transOffset = static_cast<Transformation*>(args[7].ptr());
  }

  size_t Nsegments = segments.length();
  size_t Nc = colors.length();
  size_t Nlw = linewidths.length();
  size_t Naa = antialiaseds.length();
  size_t Noffsets = 0;
  size_t N = Nsegments;

  if (usingOffsets) {
    Noffsets = offsets.length();
    if (Noffsets>Nsegments) N = Noffsets;
  }
  

  Py::Tuple xyo, pos;
  for (size_t i=0; i<N; ++i) {
    
    pos = Py::Tuple(segments[i%Nsegments]);
    double x0 = Py::Float(pos[0]);
    double y0 = Py::Float(pos[1]);
    double x1 = Py::Float(pos[2]);
    double y1 = Py::Float(pos[3]);


    std::pair<double, double> xy = transform->operator()(x0,y0);
    x0 = xy.first;
    y0 = xy.second;

    xy = transform->operator()(x1,y1);
    x1 = xy.first;
    y1 = xy.second;

    if (usingOffsets) {
      xyo = Py::Tuple(offsets[i%Noffsets]);
      double xo = Py::Float(xyo[0]);
      double yo = Py::Float(xyo[1]);
      std::pair<double, double> xy = transOffset->operator()(xo,yo);
      x0 += xy.first;
      y0 += xy.second;
      x1 += xy.first;
      y1 += xy.second;
      
    }
    //snap x to pixel for verical lines
    if (x0==x1) {
      x0 = (int)x0 + 0.5;
      x1 = (int)x1 + 0.5;
    }
    
    //snap y to pixel for horizontal lines
    if (y0==y1) {
      y0 = (int)y0 + 0.5;
      y1 = (int)y1 + 0.5;
    }

      
    agg::path_storage path;
    path.move_to(x0, height-y0);
    path.line_to(x1, height-y1);

    agg::conv_stroke<agg::path_storage> stroke(path);
    //stroke.line_cap(cap);
    //stroke.line_join(join);
    double lw = points_to_pixels ( Py::Float( linewidths[i%Nlw] ) );
    
    stroke.width(lw);
    theRasterizer->add_path(stroke);

    // get the color and render
    Py::Tuple rgba = Py::Tuple(colors[ i%Nc]);
    double r = Py::Float(rgba[0]);
    double g = Py::Float(rgba[1]);
    double b = Py::Float(rgba[2]); 
    double a = Py::Float(rgba[3]);
    agg::rgba color(r, g, b, a); 

    // render antialiased or not
    int isaa = Py::Int(antialiaseds[i%Naa]);
    if ( isaa ) {
      theRenderer->color(color);    
      theRasterizer->render(*slineP8, *theRenderer); 
    }
    else {
      rendererBin->color(color);    
      theRasterizer->render(*slineBin, *rendererBin); 
    }
  } //for every segment
  return Py::Object();
}