void bicriteria_as_coreset(
    const wplist& src,
    wplist bic,
    const csize_t dstsize,
    wplist& dst) {
  typedef wplist::const_iterator citer;
  typedef wplist::iterator iter;
  bic.resize(dstsize - dst.size());
  for (iter it = bic.begin(); it != bic.end(); ++it) {
    it->weight = 0;
  }
  for (iter it = dst.begin(); it != dst.end(); ++it) {
    pair<int, double> m = min_dist(*it, bic);
    bic[m.first].weight -= it->weight;
  }
  for (citer it = src.begin(); it != src.end(); ++it) {
    pair<int, double> m = min_dist(*it, bic);
    bic[m.first].weight += it->weight;
  }
  std::copy(bic.begin(), bic.begin()+dstsize-dst.size(),
            std::back_inserter(dst));
  for (iter it = dst.begin(); it != dst.end(); ++it) {
    if (it->weight < 0) {
      it->weight = 0;
    }
  }
}
Exemple #2
0
//returns the line that
vector< pair<Line, vector<City> > > determine_closest_lines(vector<Line> &hull_lines, vector<City> &points){
//	cout << points.size() << endl; 
	vector<float> min_dist(points.size(), INT_MAX);
	vector<int> min_lines(points.size()); 
	vector< pair<Line, vector<City> > > line_city_pair; 
	for(int i = 0; i < hull_lines.size(); i++){
		pair<Line, vector<City> > temp; 
		temp.first = hull_lines[i]; 
		line_city_pair.push_back(temp); 
	} 

	for(int i = 0; i < hull_lines.size(); i++){
		for(int j = 0; j < points.size(); j++){
			double dist = hull_lines[i].ltp(points[j]);
			if(dist < min_dist[j]){
				//line_city_pair[i].second.push_back(points[j]); 		
				min_lines[j] = i; 
				min_dist[i] = dist; 
				//cout << min_dist[j] << endl;
			}
		}
	}

		for(int j = 0; j < min_dist.size();j++){
			line_city_pair[min_lines[j]].second.push_back(points[j]); 
		}

	

return line_city_pair; 
}
void kmeans_clustering_method::do_batch_update(wplist& points) {
  static jubatus::util::math::random::mtrand r;
  bool terminated = false;
  if (points.size() < k_) {
    return;
  }
  while (!terminated) {
    vector<common::sfv_t> kcenters_new(k_);
    vector<double> center_count(k_, 0);
    for (wplist::iterator it = points.begin(); it != points.end(); ++it) {
      pair<int64_t, double> m = min_dist((*it).data, kcenters_);
      scalar_mul_and_add(it->data, it->weight, kcenters_new[m.first]);
      center_count[m.first] += it->weight;
    }
    terminated = true;
    for (size_t i = 0; i < k_; ++i) {
      if (center_count[i] == 0) {
        kcenters_new[i] = kcenters_[i];
        continue;
      }
      kcenters_new[i] = scalar_dot(kcenters_new[i], 1.0 / center_count[i]);
      double d = dist(kcenters_new[i], kcenters_[i]);
      if (d > 1e-9) {
        terminated = false;
      }
    }
    kcenters_ = kcenters_new;
  }
}
Exemple #4
0
void generate_colors(int static_component,double dist_treshold){
	yuv c;
	double dist;

	randomize_yuv(-1,&c);

	for(int i=0;i<num_colors;i++){
	// attempt to create a specific contrast between the colors not sure how  well it works
		if(!i ){
			randomize_yuv(static_component,&c);
		}else{
			randomize_yuv(static_component,&c);
			int cnt=0;
			while(dist_treshold > (dist=min_dist(c,i))){
				assert(++cnt < STUCK_TRESHOLD);

				randomize_yuv(static_component,&c);
			} 
		}

		yuv_colors[i].y=c.y;
		yuv_colors[i].u=c.u;
		yuv_colors[i].v=c.v;
	}
	
	// convert the colors to rgb
	for(int i=0;i<num_colors;i++){
		yuv2rgb(&colors[i],yuv_colors[i]);
	}
}
int64_t kmeans_clustering_method::get_nearest_center_index(
    const common::sfv_t& point) const {
  if (kcenters_.empty()) {
    throw JUBATUS_EXCEPTION(not_performed());
  }

  return min_dist(point, kcenters_).first;
}
vector<wplist> kmeans_clustering_method::get_clusters(
    const wplist& points) const {
  vector<wplist> ret(k_);
  for (wplist::const_iterator it = points.begin(); it != points.end(); ++it) {
    pair<int64_t, double> m = min_dist(it->data, kcenters_);
    ret[m.first].push_back(*it);
  }
  return ret;
}
int64_t kmeans_clustering_method::get_nearest_center_index(
    const common::sfv_t& point) const {
  if (kcenters_.empty()) {
    throw JUBATUS_EXCEPTION(common::exception::runtime_error(
        "clustering is not performed yet"));
  }

  return min_dist(point, kcenters_).first;
}
vector<wplist> kmeans_clustering_method::get_clusters(
    const wplist& points) const {
  if (kcenters_.empty()) {
    throw JUBATUS_EXCEPTION(not_performed());
  }

  vector<wplist> ret(k_);
  for (wplist::const_iterator it = points.begin(); it != points.end(); ++it) {
    pair<int64_t, double> m = min_dist(it->data, kcenters_);
    ret[m.first].push_back(*it);
  }
  return ret;
}
void kmeans_clustering_method::initialize_centers(wplist& points) {
  if (points.size() < k_) {
    return;
  }
  kcenters_.clear();
  kcenters_.push_back(points[0].data);
  vector<double> weights;
  while (kcenters_.size() < k_) {
    weights.clear();
    for (wplist::iterator it = points.begin(); it != points.end(); ++it) {
      pair<int64_t, double> m = min_dist((*it).data, kcenters_);
      weights.push_back(m.second * it->weight);
    }
    discrete_distribution d(weights.begin(), weights.end());
    kcenters_.push_back(points[d()].data);
  }
}
void kmeans_compressor::bicriteria_to_coreset(
    wplist& src,
    wplist& bicriteria,
    csize_t dstsize,
    wplist& dst) {
  if (bicriteria.size() == 0) {
    dst = src;
    return;
  }
  double weight_sum = 0;
  double squared_min_dist_sum = 0;
  for (wplist::iterator it = src.begin(); it != src.end(); ++it) {
    std::pair<int, double> m = min_dist(*it, bicriteria);
    (*it).free_long = m.first;
    (*it).free_double = m.second;
    bicriteria.at((*it).free_long).free_double += (*it).weight;
    squared_min_dist_sum += pow((*it).free_double, 2) * (*it).weight;
    weight_sum += (*it).weight;
  }
  std::vector<double> weights;
  double sumw = 0;
  double prob = 0;
  for (wplist::iterator it = src.begin(); it != src.end(); ++it) {
    weighted_point p = *it;
    weighted_point bp = bicriteria.at(p.free_long);
    prob = get_probability(p, bp, weight_sum, squared_min_dist_sum);
    (*it).free_double = prob;
    weights.push_back(prob);
    sumw += prob;
  }

  discrete_distribution d(weights.begin(), weights.end());

  std::vector<size_t> ind(dstsize);
  std::generate(ind.begin(), ind.end(), d);

  for (std::vector<size_t>::iterator it = ind.begin(); it != ind.end(); ++it) {
    weighted_point sample = src.at(*it);
    sample.weight = 1.0 / dstsize * sumw / sample.free_double * sample.weight;
    sample.free_double = 0;
    sample.free_long = 0;
    dst.push_back(sample);
  }
}
void kmeans_compressor::get_bicriteria(
    const wplist& src, csize_t bsize, csize_t dstsize, wplist& dst) {
  timer_start();
  dst.clear();
  wplist resid = src;
  vector<double> weights(src.size());
  double r = (1 - exp(bsize*(log(bsize)-log(src.size()))/dstsize)) / 2;
  r = max(0.1, r);
  std::vector<size_t> ind(bsize);
  while (resid.size() > 1 && dst.size() < dstsize) {
    timer_start();
    weights.resize(resid.size());
    for (wplist::iterator it = resid.begin(); it != resid.end(); ++it) {
      weights[it - resid.begin()] = it->weight;
    }
    discrete_distribution d(weights.begin(), weights.end());
    std::generate(ind.begin(), ind.end(), d);

    std::sort(ind.begin(), ind.end());
    std::vector<size_t>::iterator it = std::unique(ind.begin(), ind.end());
    ind.erase(it, ind.end());

    for (it = ind.begin(); it != ind.end(); ++it) {
       weighted_point p = resid[*it];
       p.free_long = 0;
       dst.push_back(p);
    }

    for (wplist::iterator itr = resid.begin(); itr != resid.end(); ++itr) {
       (*itr).free_double = min_dist(*itr, dst).second;
    }
    std::sort(resid.begin(), resid.end(), compare_weight);
    csize_t size = (csize_t)std::min(static_cast<double>(resid.size()),
                                     static_cast<double>(resid.size()*r));
    if (size  == 0) {
      size = 1;
    }

    resid.resize(size);
  }
}
int64_t kmeans_clustering_method::get_nearest_center_index(
    const common::sfv_t& point) const {
  return min_dist(point, kcenters_).first;
}
Exemple #13
0
void ElutionPeakDetection::findLocalExtrema(const MassTrace& tr, const Size & num_neighboring_peaks, std::vector<Size> & chrom_maxes, std::vector<Size> & chrom_mins)
{
    std::vector<DoubleReal> smoothed_ints_vec(tr.getSmoothedIntensities());

    Size mt_length(smoothed_ints_vec.size());

    if (mt_length != tr.getSize())
    {
        throw Exception::InvalidValue(__FILE__, __LINE__, __PRETTY_FUNCTION__, "MassTrace was not smoothed before! Aborting...", String(smoothed_ints_vec.size()));
    }

    // first make sure that everything is cleared
    chrom_maxes.clear();
    chrom_mins.clear();

    // Extract RTs from the chromatogram and store them into into vectors for index access

    // std::cout << "neighboring peaks: " << num_neighboring_peaks << std::endl;

    //  Store indices along with smoothed_ints to keep track of the peak order
    std::multimap<DoubleReal, Size> intensity_indices;
    boost::dynamic_bitset<> used_idx(mt_length);

    for (Size i = 0; i < mt_length; ++i)
    {
        intensity_indices.insert(std::make_pair(smoothed_ints_vec[i], i));
    }


    for (std::multimap<DoubleReal, Size>::const_iterator c_it = intensity_indices.begin(); c_it != intensity_indices.end(); ++c_it)
    {
        DoubleReal ref_int = c_it->first;
        Size ref_idx = c_it->second;

        if (!(used_idx[ref_idx]) && ref_int > 0.0)
        {
            bool real_max = true;

            // iterate up the RT
            Size start_idx(0);

            if (ref_idx > num_neighboring_peaks)
            {
                start_idx = ref_idx - num_neighboring_peaks;
            }

            Size end_idx = ref_idx + num_neighboring_peaks;

            if (end_idx > mt_length)
            {
                end_idx = mt_length;
            }

            for (Size j = start_idx; j < end_idx; ++j)
            {
                if (used_idx[j])
                {
                    real_max = false;
                    break;
                }

                if (j == ref_idx)
                {
                    continue;
                }

                if (smoothed_ints_vec[j] > ref_int)
                {
                    real_max = false;
                }
            }

            if (real_max)
            {
                chrom_maxes.push_back(ref_idx);

                for (Size j = start_idx; j < end_idx; ++j)
                {
                    used_idx[j] = true;
                }
            }

        }
    }


    std::sort(chrom_maxes.begin(), chrom_maxes.end());


    if (chrom_maxes.size() > 1)
    {

        Size i(0), j(1);
        //for (Size i = 0; i < chrom_maxes.size() - 1; ++i)

        while (i < j && j < chrom_maxes.size())
        {
            // bisection
            Size left_bound(chrom_maxes[i] + 1);
            Size right_bound(chrom_maxes[j] - 1);

            while ((left_bound + 1) < right_bound)
            {
                DoubleReal mid_dist((right_bound - left_bound) / 2.0);

                Size mid_element_idx(left_bound + std::floor(mid_dist));

                DoubleReal mid_element_int = smoothed_ints_vec[mid_element_idx];

                if (mid_element_int <= smoothed_ints_vec[mid_element_idx + 1])
                {
                    right_bound = mid_element_idx;
                }
                else       // or to the right...
                {
                    left_bound = mid_element_idx;
                }

            }

            Size min_rt((smoothed_ints_vec[left_bound] < smoothed_ints_vec[right_bound]) ? left_bound : right_bound);

            // check for valley depth between chromatographic peaks
            DoubleReal min_int(1.0);
            if (smoothed_ints_vec[min_rt] > min_int)
            {
                min_int = smoothed_ints_vec[min_rt];
            }

            DoubleReal left_max_int(smoothed_ints_vec[chrom_maxes[i]]);
            DoubleReal right_max_int(smoothed_ints_vec[chrom_maxes[j]]);

            DoubleReal left_rt(tr[chrom_maxes[i]].getRT());
            DoubleReal mid_rt(tr[min_rt].getRT());
            DoubleReal right_rt(tr[chrom_maxes[j]].getRT());

            DoubleReal left_dist(std::fabs(mid_rt - left_rt));
            DoubleReal right_dist(std::fabs(right_rt - mid_rt));
            DoubleReal min_dist(min_fwhm_ / 2.0);

            // out debug info
            // std::cout << tr.getLabel() << ": i,j " << i << "," << j << ":" << left_max_int << " min: " << min_int << " " << right_max_int << " l " << left_rt << " r " << right_rt << " m " << mid_rt << std::endl;



            if (left_max_int / min_int >= 2.0
                    && right_max_int / min_int >= 2.0
                    && left_dist >= min_dist
                    && right_dist >= min_dist)
            {
                chrom_mins.push_back(min_rt);

                // std::cout << "min added!" << std::endl;
                i = j;
                ++j;
            }
            else
            {
                // keep one of the chrom_maxes, iterate the other
                if (left_max_int > right_max_int)
                {
                    ++j;
                }
                else
                {
                    i = j;
                    ++j;
                }
            }

            // chrom_mins.push_back(min_rt);
        }
    }

    return;
}
Exemple #14
0
bool
CurveWarp::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc_, ProgressCallback *cb)const
{
	Point start_point=param_start_point.get(Point());
	Point end_point=param_end_point.get(Point());

	SuperCallback stageone(cb,0,9000,10000);
	SuperCallback stagetwo(cb,9000,10000,10000);
	
	RendDesc renddesc(renddesc_);
	// Untransform the render desc
	if(!cairo_renddesc_untransform(cr, renddesc))
		return false;
	
	int x,y;
	
	const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
	Point tl(renddesc.get_tl());
	Point br(renddesc.get_br());
	const int w(renddesc.get_w());
	const int h(renddesc.get_h());
	
	// find a bounding rectangle for the context we need to render
	// todo: find a better way of doing this - this way doesn't work
	Rect src_rect(transform(tl));
	Point pos1, pos2;
	Real dist, along;
	Real min_dist(999999), max_dist(-999999), min_along(999999), max_along(-999999);
	
#define UPDATE_DIST \
if (dist < min_dist) min_dist = dist; \
if (dist > max_dist) max_dist = dist; \
if (along < min_along) min_along = along; \
if (along > max_along) max_along = along
	
	// look along the top and bottom edges
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}
	
	// look along the left and right edges
	pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1];
	for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}
	
	// look along the diagonals
	const int max_wh(std::max(w,h));
	const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh);
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0], pos1[1]+=inc_y, pos2[1]-=inc_y)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}
	
#if 0
	// look at each blinepoint
	std::vector<synfig::BLinePoint>::const_iterator iter;
	for (iter=bline.begin(); iter!=bline.end(); iter++)
		src_rect.expand(transform(iter->get_vertex()+origin, &dist, &along)); UPDATE_DIST;
#endif
	
	Point src_tl(src_rect.get_min());
	Point src_br(src_rect.get_max());
	
	Vector ab((end_point - start_point).norm());
	Angle::tan ab_angle(ab[1], ab[0]);
	
	Real used_length = max_along - min_along;
	Real render_width = max_dist - min_dist;
	
	int src_w = (abs(used_length*Angle::cos(ab_angle).get()) +
				 abs(render_width*Angle::sin(ab_angle).get())) / abs(pw);
	int src_h = (abs(used_length*Angle::sin(ab_angle).get()) +
				 abs(render_width*Angle::cos(ab_angle).get())) / abs(ph);
	
	Real src_pw((src_br[0] - src_tl[0]) / src_w);
	Real src_ph((src_br[1] - src_tl[1]) / src_h);
	
	if (src_pw > abs(pw))
	{
		src_w = int((src_br[0] - src_tl[0]) / abs(pw));
		src_pw = (src_br[0] - src_tl[0]) / src_w;
	}
	
	if (src_ph > abs(ph))
	{
		src_h = int((src_br[1] - src_tl[1]) / abs(ph));
		src_ph = (src_br[1] - src_tl[1]) / src_h;
	}
	
#define MAXPIX 10000
	if (src_w > MAXPIX) src_w = MAXPIX;
	if (src_h > MAXPIX) src_h = MAXPIX;
	
	// this is an attempt to remove artifacts around tile edges - the
	// cubic interpolation uses at most 2 pixels either side of the
	// target pixel, so add an extra 2 pixels around the tile on all
	// sides
	src_tl -= (Point(src_pw,src_ph)*2);
	src_br += (Point(src_pw,src_ph)*2);
	src_w += 4;
	src_h += 4;
	src_pw = (src_br[0] - src_tl[0]) / src_w;
	src_ph = (src_br[1] - src_tl[1]) / src_h;
	
	// set up a renddesc for the context to render
	RendDesc src_desc(renddesc);
	//src_desc.clear_flags();
	src_desc.set_tl(src_tl);
	src_desc.set_br(src_br);
	src_desc.set_wh(src_w, src_h);
	
	
	// New expanded renddesc values
	const double wpw=src_desc.get_pw();
	const double wph=src_desc.get_ph();
	const double wtlx=src_desc.get_tl()[0];
	const double wtly=src_desc.get_tl()[1];

	// render the context onto a new surface
	
	cairo_surface_t* csource, *cresult;
	csource=cairo_surface_create_similar(cairo_get_target(cr),CAIRO_CONTENT_COLOR_ALPHA, src_w, src_h);
	cresult=cairo_surface_create_similar(cairo_get_target(cr),CAIRO_CONTENT_COLOR_ALPHA, w, h);
	cairo_t *subcr=cairo_create(csource);
	cairo_scale(subcr, 1/wpw, 1/wph);
	cairo_translate(subcr, -wtlx, -wtly);

	if(!context.accelerated_cairorender(subcr,quality,src_desc,&stageone))
		return false;
	// don't needed anymore
	cairo_destroy(subcr);
	//access to pixels
	CairoSurface source(csource);
	source.map_cairo_image();
	
	CairoSurface result(cresult);
	result.map_cairo_image();
	float u,v;
	Point pos, tmp;
		
	if(quality<=4)				// CUBIC
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
				else
					result[y][x]=source.cubic_sample_cooked(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else if (quality<=6)		// INTERPOLATION_LINEAR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
				else
					result[y][x]=source.linear_sample_cooked(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else						// NEAREST_NEIGHBOR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
				else
					result[y][x]=source[floor_to_int(v)][floor_to_int(u)];
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	
	result.unmap_cairo_image();
	source.unmap_cairo_image();
	
	cairo_surface_destroy(csource);
	// Now paint it on the context
	cairo_save(cr);
	
	cairo_translate(cr, tl[0], tl[1]);
	cairo_scale(cr, pw, ph);
	cairo_set_source_surface(cr, cresult, 0, 0);
	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
	cairo_paint(cr);
	
	cairo_restore(cr);
	
	cairo_surface_destroy(cresult);
	
	// Mark our progress as finished
	if(cb && !cb->amount_complete(10000,10000))
		return false;
	
	return true;
}
Exemple #15
0
bool
CurveWarp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
	Point start_point=param_start_point.get(Point());
	Point end_point=param_end_point.get(Point());

	SuperCallback stageone(cb,0,9000,10000);
	SuperCallback stagetwo(cb,9000,10000,10000);

	int x,y;

	const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
	Point tl(renddesc.get_tl());
	Point br(renddesc.get_br());
	const int w(renddesc.get_w());
	const int h(renddesc.get_h());

	// find a bounding rectangle for the context we need to render
	// todo: find a better way of doing this - this way doesn't work
	Rect src_rect(transform(tl));
	Point pos1, pos2;
	Real dist, along;
	Real min_dist(999999), max_dist(-999999), min_along(999999), max_along(-999999);

#define UPDATE_DIST \
	if (dist < min_dist) min_dist = dist; \
	if (dist > max_dist) max_dist = dist; \
	if (along < min_along) min_along = along; \
	if (along > max_along) max_along = along

	// look along the top and bottom edges
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}

	// look along the left and right edges
	pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1];
	for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}

	// look along the diagonals
	const int max_wh(std::max(w,h));
	const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh);
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0], pos1[1]+=inc_y, pos2[1]-=inc_y)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}

#if 0
	// look at each blinepoint
	std::vector<synfig::BLinePoint>::const_iterator iter;
	for (iter=bline.begin(); iter!=bline.end(); iter++)
		src_rect.expand(transform(iter->get_vertex()+origin, &dist, &along)); UPDATE_DIST;
#endif

	Point src_tl(src_rect.get_min());
	Point src_br(src_rect.get_max());

	Vector ab((end_point - start_point).norm());
	Angle::tan ab_angle(ab[1], ab[0]);

	Real used_length = max_along - min_along;
	Real render_width = max_dist - min_dist;

	int src_w = (abs(used_length*Angle::cos(ab_angle).get()) +
				 abs(render_width*Angle::sin(ab_angle).get())) / abs(pw);
	int src_h = (abs(used_length*Angle::sin(ab_angle).get()) +
				 abs(render_width*Angle::cos(ab_angle).get())) / abs(ph);

	Real src_pw((src_br[0] - src_tl[0]) / src_w);
	Real src_ph((src_br[1] - src_tl[1]) / src_h);

	if (src_pw > abs(pw))
	{
		src_w = int((src_br[0] - src_tl[0]) / abs(pw));
		src_pw = (src_br[0] - src_tl[0]) / src_w;
	}

	if (src_ph > abs(ph))
	{
		src_h = int((src_br[1] - src_tl[1]) / abs(ph));
		src_ph = (src_br[1] - src_tl[1]) / src_h;
	}

#define MAXPIX 10000
	if (src_w > MAXPIX) src_w = MAXPIX;
	if (src_h > MAXPIX) src_h = MAXPIX;

	// this is an attempt to remove artifacts around tile edges - the
	// cubic interpolation uses at most 2 pixels either side of the
	// target pixel, so add an extra 2 pixels around the tile on all
	// sides
	src_tl -= (Point(src_pw,src_ph)*2);
	src_br += (Point(src_pw,src_ph)*2);
	src_w += 4;
	src_h += 4;
	src_pw = (src_br[0] - src_tl[0]) / src_w;
	src_ph = (src_br[1] - src_tl[1]) / src_h;

	// set up a renddesc for the context to render
	RendDesc src_desc(renddesc);
	src_desc.clear_flags();
	src_desc.set_tl(src_tl);
	src_desc.set_br(src_br);
	src_desc.set_wh(src_w, src_h);

	// render the context onto a new surface
	Surface source;
	source.set_wh(src_w,src_h);
	if(!context.accelerated_render(&source,quality,src_desc,&stageone))
		return false;

	float u,v;
	Point pos, tmp;

	surface->set_wh(w,h);
	surface->clear();

	if(quality<=4)				// CUBIC
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					(*surface)[y][x]=context.get_color(tmp);
				else
					(*surface)[y][x]=source.cubic_sample(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else if (quality<=6)		// INTERPOLATION_LINEAR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					(*surface)[y][x]=context.get_color(tmp);
				else
					(*surface)[y][x]=source.linear_sample(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else						// NEAREST_NEIGHBOR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					(*surface)[y][x]=context.get_color(tmp);
				else
					(*surface)[y][x]=source[floor_to_int(v)][floor_to_int(u)];
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}

	// Mark our progress as finished
	if(cb && !cb->amount_complete(10000,10000))
		return false;

	return true;
}