//------------------------------------------------------------------- trans_affine to_affine() const { trans_affine mtx = trans_affine_translation(-m_wx1, -m_wy1); mtx *= trans_affine_scaling(m_kx, m_ky); mtx *= trans_affine_translation(m_dx1, m_dy1); return mtx; }
//-------------------------------------------------------------------- void bezier_arc_svg::init(real x0, real y0, real rx, real ry, real angle, bool large_arc_flag, bool sweep_flag, real x2, real y2) { m_radii_ok = true; if(rx < 0.0f) rx = -rx; if(ry < 0.0f) ry = -rx; // Calculate the middle point between // the current and the final points //------------------------ real dx2 = (x0 - x2) / 2.0f; real dy2 = (y0 - y2) / 2.0f; real cos_a = (real)cos(angle); real sin_a = (real)sin(angle); // Calculate (x1, y1) //------------------------ real x1 = cos_a * dx2 + sin_a * dy2; real y1 = -sin_a * dx2 + cos_a * dy2; // Ensure radii are large enough //------------------------ real prx = rx * rx; real pry = ry * ry; real px1 = x1 * x1; real py1 = y1 * y1; // Check that radii are large enough //------------------------ real radii_check = px1/prx + py1/pry; if(radii_check > 1.0f) { rx = SQRT(radii_check) * rx; ry = SQRT(radii_check) * ry; prx = rx * rx; pry = ry * ry; if(radii_check > 10.0f) m_radii_ok = false; } // Calculate (cx1, cy1) //------------------------ real sign = (large_arc_flag == sweep_flag) ? -1.0f : 1.0f; real sq = (prx*pry - prx*py1 - pry*px1) / (prx*py1 + pry*px1); real coef = sign * SQRT((sq < 0) ? 0 : sq); real cx1 = coef * ((rx * y1) / ry); real cy1 = coef * -((ry * x1) / rx); // // Calculate (cx, cy) from (cx1, cy1) //------------------------ real sx2 = (x0 + x2) / 2.0f; real sy2 = (y0 + y2) / 2.0f; real cx = sx2 + (cos_a * cx1 - sin_a * cy1); real cy = sy2 + (sin_a * cx1 + cos_a * cy1); // Calculate the start_angle (angle1) and the sweep_angle (dangle) //------------------------ real ux = (x1 - cx1) / rx; real uy = (y1 - cy1) / ry; real vx = (-x1 - cx1) / rx; real vy = (-y1 - cy1) / ry; real p, n; // Calculate the angle start //------------------------ n = SQRT(ux*ux + uy*uy); p = ux; // (1 * ux) + (0 * uy) sign = (uy < 0) ? -1.0f : 1.0f; real v = p / n; if(v < -1.0f) v = -1.0f; if(v > 1.0f) v = 1.0f; real start_angle = sign * (real)acos(v); // Calculate the sweep angle //------------------------ n = SQRT((ux*ux + uy*uy) * (vx*vx + vy*vy)); p = ux * vx + uy * vy; sign = (ux * vy - uy * vx < 0) ? -1.0f : 1.0f; v = p / n; if(v < -1.0f) v = -1.0f; if(v > 1.0f) v = 1.0f; real sweep_angle = sign * (real)acos(v); if(!sweep_flag && sweep_angle > 0) { sweep_angle -= pi * 2.0f; } else if (sweep_flag && sweep_angle < 0) { sweep_angle += pi * 2.0f; } // We can now build and transform the resulting arc //------------------------ m_arc.init(0.0f, 0.0f, rx, ry, start_angle, sweep_angle); trans_affine mtx = trans_affine_rotation(angle); mtx *= trans_affine_translation(cx, cy); for(unsigned i = 2; i < m_arc.num_vertices()-2; i += 2) { mtx.transform(m_arc.vertices() + i, m_arc.vertices() + i + 1); } // We must make sure that the starting and ending points // exactly coincide with the initial (x0,y0) and (x2,y2) m_arc.vertices()[0] = x0; m_arc.vertices()[1] = y0; if(m_arc.num_vertices() > 2) { m_arc.vertices()[m_arc.num_vertices() - 2] = x2; m_arc.vertices()[m_arc.num_vertices() - 1] = y2; } }