| 103 | } |
| 104 | |
| 105 | void Path::arcTo(float rx, float ry, float x_axis_rotation, bool large_arc, bool sweep_flag, |
| 106 | Point point, bool relative) { |
| 107 | rx = std::abs(rx); |
| 108 | ry = std::abs(ry); |
| 109 | if (rx == 0.0f || ry == 0.0f) { |
| 110 | lineTo(point); |
| 111 | return; |
| 112 | } |
| 113 | |
| 114 | if (currentPath().points.empty()) |
| 115 | addPoint(last_point_); |
| 116 | |
| 117 | Point from = last_point_; |
| 118 | if (relative) |
| 119 | point += last_point_; |
| 120 | |
| 121 | auto ellipse_rotation = Matrix::rotation(x_axis_rotation); |
| 122 | Point delta = ellipse_rotation.transposed() * (point - from); |
| 123 | float radius_ratio = rx / ry; |
| 124 | delta.y *= radius_ratio; |
| 125 | |
| 126 | float length = delta.length(); |
| 127 | if (length == 0.0f) |
| 128 | return; |
| 129 | |
| 130 | float radius = std::max(length * 0.5f, rx); |
| 131 | float center_offset = std::sqrt(std::max(0.0f, radius * radius - length * length * 0.25f)); |
| 132 | Point normal = Point(delta.y, -delta.x) / length; |
| 133 | if (large_arc != sweep_flag) |
| 134 | normal = -normal; |
| 135 | |
| 136 | Point center = delta * 0.5f + normal * center_offset; |
| 137 | float arc_angle = 2.0f * std::asin(length * 0.5f / radius); |
| 138 | |
| 139 | if (large_arc) |
| 140 | arc_angle = 2.0f * kPi - arc_angle; |
| 141 | if (!sweep_flag) |
| 142 | arc_angle = -arc_angle; |
| 143 | |
| 144 | Point adjusted_radius = resolution_matrix_ * Point(rx, ry); |
| 145 | float max_radius = std::max(std::abs(adjusted_radius.x), std::abs(adjusted_radius.y)); |
| 146 | float max_delta_radians = 2.0f * clampedACos(1.0f - error_tolerance_ / max_radius); |
| 147 | int num_points = std::ceil(std::abs(arc_angle) / max_delta_radians); |
| 148 | |
| 149 | std::complex<float> position(-center.x, -center.y); |
| 150 | float angle_delta = arc_angle / num_points; |
| 151 | std::complex<float> rotation = std::polar(1.0f, angle_delta); |
| 152 | |
| 153 | for (int i = 0; i < num_points; ++i) { |
| 154 | position *= rotation; |
| 155 | Point p = center + Point(position.real(), position.imag()); |
| 156 | p.y /= radius_ratio; |
| 157 | p = ellipse_rotation * p + from; |
| 158 | addPoint(p); |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | static float parseNumber(const std::string& str, size_t& i, bool bit_flags = false) { |
no test coverage detected