std::unique_ptr<PathObject> FollowPathToolHelper::updateFollowing(const PathCoord& end_coord) { std::unique_ptr<PathObject> result; if (path && path->findPartIndexForIndex(end_coord.index) == part_index) { // Update end_clen auto new_end_clen = end_coord.clen; const auto& part = path->parts()[part_index]; if (part.isClosed()) { // Positive length to add to end_clen to get to new_end_clen with wrapping auto path_length = part.length(); auto forward_diff = fmod_pos(new_end_clen - end_clen, path_length); auto delta_forward = forward_diff >= 0 && forward_diff < 0.5f * path_length; if (delta_forward && !drag_forward && fmod_pos(end_clen - start_clen, path_length) > 0.5f * path_length && fmod_pos(new_end_clen - start_clen, path_length) <= 0.5f * path_length ) { drag_forward = true; } else if (!delta_forward && drag_forward && fmod_pos(end_clen - start_clen, path_length) <= 0.5f * path_length && fmod_pos(new_end_clen - start_clen, path_length) > 0.5f * path_length) { drag_forward = false; } } else { drag_forward = new_end_clen >= start_clen; } end_clen = new_end_clen; if (end_clen != start_clen) { // Create output path result.reset(new PathObject { part }); if (drag_forward) { result->changePathBounds(0, start_clen, end_clen); } else { result->changePathBounds(0, end_clen, start_clen); result->reverse(); } } } return result; }
void DrawRectangleTool::updateRectangle() { double angle = angle_helper->getConstrainedCursorPosMap(constrained_pos_map, constrained_pos_map); if (angles.size() == 1) { // Update vectors and angles forward_vector = constrained_pos_map - MapCoordF(preview_path->getCoordinate(0)); forward_vector.normalize(); angles.back() = -forward_vector.angle(); // Update rectangle MapCoord coord = MapCoord(constrained_pos_map); coord.setDashPoint(draw_dash_points); preview_path->setCoordinate(1, coord); } else { // Update vectors and angles forward_vector = MapCoordF::fromPolar(1.0, -angle); angles.back() = angle; // Update rectangle auto cur_point_index = angles.size(); deleteClosePoint(); float forward_dist = MapCoordF::dotProduct(forward_vector, constrained_pos_map - MapCoordF(preview_path->getCoordinate(cur_point_index - 1))); MapCoord coord = preview_path->getCoordinate(cur_point_index - 1) + MapCoord(forward_dist * forward_vector); snapped_to_line = false; float best_snap_distance_sq = std::numeric_limits<float>::max(); if (ctrl_pressed && angles.size() > 2) { // Try to snap to existing lines MapCoord original_coord = coord; for (int i = 0; i < (int)angles.size() - 1; ++i) { MapCoordF direction(100, 0); direction.rotate(-angles[i]); int num_steps; double angle_step, angle_offset = 0; if (i == 0 || qAbs(qAbs(fmod_pos(angles[i], M_PI) - fmod_pos(angles[i-1], M_PI)) - (M_PI / 2)) < 0.1) { num_steps = 2; angle_step = M_PI/2; } else { num_steps = 4; angle_step = M_PI/4; } for (int k = 0; k < num_steps; ++k) { if (qAbs(fmod_pos(angle, M_PI) - fmod_pos(angles[i] - (angle_offset + k * angle_step), M_PI)) < 0.1) continue; MapCoordF rotated_direction = direction; rotated_direction.rotate(angle_offset + k * angle_step); QLineF a(QPointF(preview_path->getCoordinate(cur_point_index - 1)), MapCoordF(preview_path->getCoordinate(cur_point_index - 1)) + forward_vector); QLineF b(QPointF(preview_path->getCoordinate(i)), MapCoordF(preview_path->getCoordinate(i)) + rotated_direction); QPointF intersection_point; QLineF::IntersectType intersection_type = a.intersect(b, &intersection_point); if (intersection_type == QLineF::NoIntersection) continue; float snap_distance_sq = original_coord.distanceSquaredTo(MapCoord(intersection_point)); if (snap_distance_sq > best_snap_distance_sq) continue; best_snap_distance_sq = snap_distance_sq; coord = MapCoord(intersection_point); snapped_to_line_a = coord; snapped_to_line_b = coord + MapCoord(rotated_direction); snapped_to_line = true; } } } coord.setDashPoint(draw_dash_points); preview_path->setCoordinate(cur_point_index, coord); auto close_vector = calculateClosingVector(); float close_dist = MapCoordF::dotProduct(close_vector, MapCoordF(preview_path->getCoordinate(0) - preview_path->getCoordinate(cur_point_index))); coord = preview_path->getCoordinate(cur_point_index) + MapCoord(close_dist * close_vector); coord.setDashPoint(draw_dash_points); preview_path->setCoordinate(cur_point_index + 1, coord); preview_path->parts().front().setClosed(true, true); } updatePreviewPath(); updateDirtyRect(); }
bool DrawRectangleTool::drawingParallelTo(double angle) const { const double epsilon = 0.01; double cur_angle = angles[angles.size() - 1]; return qAbs(fmod_pos(cur_angle, M_PI) - fmod_pos(angle, M_PI)) < epsilon; }