void BuildEndCap( double x0, double y0, double x1, double y1, List <Vector> outputVectors) { switch (LineCapStyle) { default: throw new NotSupportedException(); case LineCap.Butt: break; case LineCap.Square: break; case LineCap.Round: { //------------------------ //x0,y0 -> end of line 1 //x1,y1 -> end of line 2 //------------------------ double c_x = (x0 + x1) / 2; double c_y = (y0 + y1) / 2; Vector2 delta = new Vector2(x1 - c_x, y1 - c_y); ArcGenerator.GenerateArcNew(outputVectors, c_x, c_y, delta, AggMath.deg2rad(180)); } break; } }
public void SetFilterOffset(double dx, double dy) { m_dx_dbl = dx; m_dy_dbl = dy; m_dx_int = AggMath.iround(dx * img_subpix_const.SCALE); m_dy_int = AggMath.iround(dy * img_subpix_const.SCALE); }
//bool AutoClose //{ // get { return m_auto_close; } // set { this.m_auto_close = value; } //} //-------------------------------------------------------------------- public void ResetGamma(IGammaFunction gamma_function) { for (int i = AA_SCALE - 1; i >= 0; --i) { m_gammaLut[i] = (int)AggMath.uround( gamma_function.GetGamma((float)(i) / AA_MASK) * AA_MASK); } }
void SetGamma(float g) { m_gamma = g; float inv_g = (float)(1.0 / g); for (int i = GAMMA_SIZE - 1; i >= 0; --i) { m_dir_gamma[i] = (byte)AggMath.uround(Math.Pow(i / (float)GAMMA_MASK, m_gamma) * (float)GAMMA_MASK); m_inv_gamma[i] = (byte)AggMath.uround(Math.Pow(i / (float)GAMMA_MASK, inv_g) * (float)GAMMA_MASK); } }
//-------------------------------------------------------------------- public void Prepare() { CoordAndColor c0, c1, c2; base.LoadArrangedVertices(out c0, out c1, out c2); m_y2 = (int)c1.y; m_swap = AggMath.Cross(c0.x, c0.y, c2.x, c2.y, c1.x, c1.y) < 0.0; m_rgba1.Init(c0, c2); m_rgba2.Init(c0, c1); m_rgba3.Init(c1, c2); }
public bool IsEqual(Vertex2d val) { return(AggMath.calc_distance(x, y, val.x, val.y) <= AggMath.VERTEX_DISTANCE_EPSILON); //if ((dist = AggMath.calc_distance(x, y, val.x, val.y)) > AggMath.VERTEX_DISTANCE_EPSILON) //{ // //diff enough=> this is NOT equal with val // return false; //} //else //{ // //not diff enough => this is equal (with val) // dist = 1.0 / AggMath.VERTEX_DISTANCE_EPSILON; // return true; //} }
//-------------------------------------------------------------------- public SpanGenGradient(ISpanInterpolator inter, IGradientValueCalculator gvc, IGradientColorsProvider m_colorsProvider, double d1, double d2) { this.m_interpolator = inter; this.m_grValueCalculator = gvc; this.m_colorsProvider = m_colorsProvider; m_d1 = AggMath.iround(d1 * GR_SUBPIX_SCALE); m_d2 = AggMath.iround(d2 * GR_SUBPIX_SCALE); dd = m_d2 - m_d1; if (dd < 1) { dd = 1; } stepRatio = (float)m_colorsProvider.GradientSteps / (float)dd; }
//helper class for generate arc // public static void GenerateArcNew(List <Vector> output, double cx, double cy, Vector2 startDelta, double sweepAngleRad) { //TODO: review here *** int nsteps = 4; double eachStep = AggMath.rad2deg(sweepAngleRad) / nsteps; double angle = 0; for (int i = 0; i < nsteps; ++i) { Vector2 newPerpend = startDelta.RotateInDegree(angle); Vector2 newpos = new Vector2(cx + newPerpend.x, cy + newPerpend.y); output.Add(new Vector(newpos.x, newpos.y)); angle += eachStep; } }
public void Calculate(double y) { double k = (y - m_y1) * m_1dy; if (k < 0.0) { k = 0.0; } if (k > 1.0) { k = 1.0; } m_r = m_r1 + AggMath.iround(m_dr * k); m_g = m_g1 + AggMath.iround(m_dg * k); m_b = m_b1 + AggMath.iround(m_db * k); m_a = m_a1 + AggMath.iround(m_da * k); m_x = AggMath.iround((m_x1 + m_dx * k) * (double)SUBPIXEL_SCALE); }
//-------------------------------------------------------------------- // Sets the triangle and dilates it if needed. // The trick here is to calculate beveled joins in the vertices of the // triangle and render it as a 6-vertex polygon. // It's necessary to achieve numerical stability. // However, the coordinates to interpolate colors are calculated // as miter joins (calc_intersection). public void SetTriangle(double x1, double y1, double x2, double y2, double x3, double y3, double d) { m_coord_0.x = m_x[0] = x1; m_coord_0.y = m_y[0] = y1; m_coord_1.x = m_x[1] = x2; m_coord_1.y = m_y[1] = y2; m_coord_2.x = m_x[2] = x3; m_coord_2.y = m_y[2] = y3; m_cmd[0] = VertexCmd.MoveTo; m_cmd[1] = VertexCmd.LineTo; m_cmd[2] = VertexCmd.LineTo; m_cmd[3] = VertexCmd.Stop; if (d != 0.0) { AggMath.DilateTriangle(m_coord_0.x, m_coord_0.y, m_coord_1.x, m_coord_1.y, m_coord_2.x, m_coord_2.y, m_x, m_y, d); AggMath.CalcIntersect(m_x[4], m_y[4], m_x[5], m_y[5], m_x[0], m_y[0], m_x[1], m_y[1], out m_coord_0.x, out m_coord_0.y); AggMath.CalcIntersect(m_x[0], m_y[0], m_x[1], m_y[1], m_x[2], m_y[2], m_x[3], m_y[3], out m_coord_1.x, out m_coord_1.y); AggMath.CalcIntersect(m_x[2], m_y[2], m_x[3], m_y[3], m_x[4], m_y[4], m_x[5], m_y[5], out m_coord_2.x, out m_coord_2.y); m_cmd[3] = VertexCmd.LineTo; m_cmd[4] = VertexCmd.LineTo; m_cmd[5] = VertexCmd.LineTo; m_cmd[6] = VertexCmd.Stop; } }
void CreateMiter(VertexStore output, VertexDistance v0, VertexDistance v1, VertexDistance v2, double dx1, double dy1, double dx2, double dy2, LineJoin lj, double mlimit, double dbevel) { double xi = v1.x; double yi = v1.y; double di = 1; double lim = m_width_abs * mlimit; bool miter_limit_exceeded = true; // Assume the worst bool intersection_failed = true; // Assume the worst if (AggMath.CalcIntersect(v0.x + dx1, v0.y - dy1, v1.x + dx1, v1.y - dy1, v1.x + dx2, v1.y - dy2, v2.x + dx2, v2.y - dy2, out xi, out yi)) { // Calculation of the intersection succeeded //--------------------- di = AggMath.calc_distance(v1.x, v1.y, xi, yi); if (di <= lim) { // Inside the miter limit //--------------------- AddVertex(output, xi, yi); miter_limit_exceeded = false; } intersection_failed = false; } else { // Calculation of the intersection failed, most probably // the three points lie one straight line. // First check if v0 and v2 lie on the opposite sides of vector: // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular // to the line determined by vertices v0 and v1. // This condition determines whether the next line segments continues // the previous one or goes back. //---------------- double x2 = v1.x + dx1; double y2 = v1.y - dy1; if ((AggMath.Cross(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) == (AggMath.Cross(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0)) { // This case means that the next segment continues // the previous one (straight line) //----------------- AddVertex(output, v1.x + dx1, v1.y - dy1); miter_limit_exceeded = false; } } if (miter_limit_exceeded) { // Miter limit exceeded //------------------------ switch (lj) { case LineJoin.MiterRevert: // For the compatibility with SVG, PDF, etc, // we use a simple bevel join instead of // "smart" bevel //------------------- AddVertex(output, v1.x + dx1, v1.y - dy1); AddVertex(output, v1.x + dx2, v1.y - dy2); break; case LineJoin.MiterRound: CreateArc(output, v1.x, v1.y, dx1, -dy1, dx2, -dy2); break; default: // If no miter-revert, calculate new dx1, dy1, dx2, dy2 //---------------- if (intersection_failed) { mlimit *= m_width_sign; AddVertex(output, v1.x + dx1 + dy1 * mlimit, v1.y - dy1 + dx1 * mlimit); AddVertex(output, v1.x + dx2 - dy2 * mlimit, v1.y - dy2 - dx2 * mlimit); } else { double x1 = v1.x + dx1; double y1 = v1.y - dy1; double x2 = v1.x + dx2; double y2 = v1.y - dy2; di = (lim - dbevel) / (di - dbevel); AddVertex(output, x1 + (xi - x1) * di, y1 + (yi - y1) * di); AddVertex(output, x2 + (xi - x2) * di, y2 + (yi - y2) * di); } break; } } }
public void CreateJoin(VertexStore output, VertexDistance v0, VertexDistance v1, VertexDistance v2, double len1, double len2) { double dx1 = m_width * (v1.y - v0.y) / len1; double dy1 = m_width * (v1.x - v0.x) / len1; double dx2 = m_width * (v2.y - v1.y) / len2; double dy2 = m_width * (v2.x - v1.x) / len2; output.Clear(); double cp = AggMath.Cross(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y); if (cp != 0 && (cp > 0) == (m_width > 0)) { // Inner join //--------------- double limit = ((len1 < len2) ? len1 : len2) / m_width_abs; if (limit < m_inner_miter_limit) { limit = m_inner_miter_limit; } switch (m_inner_join) { default: // inner_bevel AddVertex(output, v1.x + dx1, v1.y - dy1); AddVertex(output, v1.x + dx2, v1.y - dy2); break; case InnerJoin.Miter: CreateMiter(output, v0, v1, v2, dx1, dy1, dx2, dy2, LineJoin.MiterRevert, limit, 0); break; case InnerJoin.Jag: case InnerJoin.Round: cp = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2); if (cp < len1 * len1 && cp < len2 * len2) { CreateMiter(output, v0, v1, v2, dx1, dy1, dx2, dy2, LineJoin.MiterRevert, limit, 0); } else { if (m_inner_join == InnerJoin.Jag) { AddVertex(output, v1.x + dx1, v1.y - dy1); AddVertex(output, v1.x, v1.y); AddVertex(output, v1.x + dx2, v1.y - dy2); } else { AddVertex(output, v1.x + dx1, v1.y - dy1); AddVertex(output, v1.x, v1.y); CreateArc(output, v1.x, v1.y, dx2, -dy2, dx1, -dy1); AddVertex(output, v1.x, v1.y); AddVertex(output, v1.x + dx2, v1.y - dy2); } } break; } } else { // Outer join //--------------- // Calculate the distance between v1 and // the central point of the bevel line segment //--------------- double dx = (dx1 + dx2) / 2; double dy = (dy1 + dy2) / 2; double dbevel = Math.Sqrt(dx * dx + dy * dy); if (m_line_join == LineJoin.Round || m_line_join == LineJoin.Bevel) { // This is an optimization that reduces the number of points // in cases of almost collinear segments. If there's no // visible difference between bevel and miter joins we'd rather // use miter join because it adds only one point instead of two. // // Here we calculate the middle point between the bevel points // and then, the distance between v1 and this middle point. // At outer joins this distance always less than stroke width, // because it's actually the height of an isosceles triangle of // v1 and its two bevel points. If the difference between this // width and this value is small (no visible bevel) we can // add just one point. // // The constant in the expression makes the result approximately // the same as in round joins and caps. You can safely comment // out this entire "if". //------------------- if (m_approx_scale * (m_width_abs - dbevel) < m_width_eps) { if (AggMath.CalcIntersect(v0.x + dx1, v0.y - dy1, v1.x + dx1, v1.y - dy1, v1.x + dx2, v1.y - dy2, v2.x + dx2, v2.y - dy2, out dx, out dy)) { AddVertex(output, dx, dy); } else { AddVertex(output, v1.x + dx1, v1.y - dy1); } return; } } switch (m_line_join) { case LineJoin.Miter: case LineJoin.MiterRevert: case LineJoin.MiterRound: CreateMiter(output, v0, v1, v2, dx1, dy1, dx2, dy2, m_line_join, m_miter_limit, dbevel); break; case LineJoin.Round: CreateArc(output, v1.x, v1.y, dx1, -dy1, dx2, -dy2); break; default: // Bevel join AddVertex(output, v1.x + dx1, v1.y - dy1); AddVertex(output, v1.x + dx2, v1.y - dy2); break; } } }
public double CalLen(Vertex2d another) { return(AggMath.calc_distance(x, y, another.x, another.y)); }
//--------------------------------- //from vector clipper static int upscale(double v) { return(AggMath.iround(v * poly_subpix.SCALE)); }