Exemplo n.º 1
0
void DrawPathTool::updateDrawHover()
{
	if (!shift_pressed)
		angle_helper->getConstrainedCursorPosMap(cur_pos_map, constrained_pos_map);
	if (!previous_point_is_curve_point && !left_mouse_down && editingInProgress())
	{
		// Show a line to the cursor position as preview
		hidePreviewPoints();
		
		if (!path_has_preview_point)
		{
			preview_path->addCoordinate(MapCoord(constrained_pos_map));
			path_has_preview_point = true;
		}
		preview_path->setCoordinate(preview_path->getCoordinateCount() - 1, MapCoord(constrained_pos_map));
		
		updatePreviewPath();
		updateDirtyRect();	// TODO: Possible optimization: mark only the last segment as dirty
	}
	else if (previous_point_is_curve_point && !left_mouse_down && editingInProgress())
	{
		setPreviewPointsPosition(constrained_pos_map, 1);
		updateDirtyRect();
	}
}
Exemplo n.º 2
0
void DrawPathTool::updateFollowing()
{
	PathCoord path_coord;
	float distance_sq;
	const auto& part = follow_object->parts()[follow_helper->getPartIndex()];
	follow_object->calcClosestPointOnPath(cur_pos_map, distance_sq, path_coord, part.first_index, part.last_index);
	auto followed_path = follow_helper->updateFollowing(path_coord);
	
	// Append the temporary object to the preview object at follow_start_index
	// 1. Delete everything appended, except for the point where following started
	//    (thus avoiding deletion of the whole part).
	for (auto i = preview_path->getCoordinateCount() - 1;
	     i > follow_start_index + 1;
	     i = preview_path->getCoordinateCount() - 1)
	{
		preview_path->deleteCoordinate(i, false);
	}
	// 2. Merge segments at the point where following started.
	if (followed_path)
	{
		preview_path->connectPathParts(preview_path->findPartIndexForIndex(follow_start_index),
		                               followed_path.get(), 0, false, true);
	}
	updatePreviewPath();
	hidePreviewPoints();
	updateDirtyRect();
}
Exemplo n.º 3
0
void DrawPathTool::createPreviewCurve(MapCoord position, float direction)
{
	if (!path_has_preview_point)
	{
		int last = preview_path->getCoordinateCount() - 1;
		(preview_path->getCoordinate(last)).setCurveStart(true);
		
		preview_path->addCoordinate(MapCoord(0, 0));
		preview_path->addCoordinate(MapCoord(0, 0));
		if (draw_dash_points)
			position.setDashPoint(true);
		position.setCurveStart(false);
		preview_path->addCoordinate(position);
		
		path_has_preview_point = true;
	}
	
	// Adjust the preview curve
	int last = preview_path->getCoordinateCount() - 1;
	MapCoord previous_point = preview_path->getCoordinate(last - 3);
	MapCoord last_point = preview_path->getCoordinate(last);
	
	double bezier_handle_distance = BEZIER_HANDLE_DISTANCE * previous_point.distanceTo(last_point);
	
	preview_path->setCoordinate(last - 2, MapCoord(previous_point.x() - bezier_handle_distance * sin(previous_point_direction),
	                                               previous_point.y() - bezier_handle_distance * cos(previous_point_direction)));
	preview_path->setCoordinate(last - 1, MapCoord(last_point.x() + bezier_handle_distance * sin(direction),
	                                               last_point.y() + bezier_handle_distance * cos(direction)));
	updatePreviewPath();	
}
Exemplo n.º 4
0
void DrawCircleTool::updateCircle()
{
	MapCoordF first_pos_map;
	if (start_from_center)
		first_pos_map = circle_start_pos_map + (circle_start_pos_map - opposite_pos_map);
	else
		first_pos_map = circle_start_pos_map;
	
	float radius = 0.5f * first_pos_map.distanceTo(opposite_pos_map);
	float kappa = BEZIER_KAPPA;
	float m_kappa = 1 - BEZIER_KAPPA;
	
	MapCoordF across = opposite_pos_map - first_pos_map;
	across.setLength(radius);
	MapCoordF right = across.perpRight();
	
	float right_radius = radius;
	if (second_point_set && dragging)
	{
		if (right.length() < 1e-8)
			right_radius = 0;
		else
		{
			MapCoordF to_cursor = cur_pos_map - first_pos_map;
			right_radius = MapCoordF::dotProduct(to_cursor, right) / right.length();
		}
	}
	right.setLength(right_radius);
	
	preview_path->clearCoordinates();
	preview_path->addCoordinate(MapCoord(first_pos_map, MapCoord::CurveStart));
	preview_path->addCoordinate(MapCoord(first_pos_map + kappa * right));
	preview_path->addCoordinate(MapCoord(first_pos_map + right + m_kappa * across));
	preview_path->addCoordinate(MapCoord(first_pos_map + right + across, MapCoord::CurveStart));
	preview_path->addCoordinate(MapCoord(first_pos_map + right + (1 + kappa) * across));
	preview_path->addCoordinate(MapCoord(first_pos_map + kappa * right + 2 * across));
	preview_path->addCoordinate(MapCoord(first_pos_map + 2 * across, MapCoord::CurveStart));
	preview_path->addCoordinate(MapCoord(first_pos_map - kappa * right + 2 * across));
	preview_path->addCoordinate(MapCoord(first_pos_map - right + (1 + kappa) * across));
	preview_path->addCoordinate(MapCoord(first_pos_map - right + across, MapCoord::CurveStart));
	preview_path->addCoordinate(MapCoord(first_pos_map - right + m_kappa * across));
	preview_path->addCoordinate(MapCoord(first_pos_map - kappa * right));
	preview_path->parts().front().setClosed(true, false);
	
	updatePreviewPath();
	setDirtyRect();
}
Exemplo n.º 5
0
void DrawPathTool::updateAngleHelper()
{
	if (picked_angle)
		return;
	
	if (!preview_path
	    || (updatePreviewPath(), preview_path->parts().empty()))
	{
		angle_helper->clearAngles();
		angle_helper->addDefaultAnglesDeg(0);
		return;
	}
	
	const auto& part = preview_path->parts().back();
	
	bool rectangular_stepping = true;
	double angle;
	if (part.size() >= 2)
	{
		bool ok = false;
		MapCoordF tangent = part.calculateTangent(part.size()-1, true, ok);
		if (!ok)
			tangent = MapCoordF(1, 0);
		angle = -tangent.angle();
	}
	else
	{
		if (previous_point_is_curve_point)
			angle = previous_point_direction;
		else
		{
			angle = 0;
			rectangular_stepping = false;
		}
	}
	
	if (!part.empty())
		angle_helper->setCenter(part.coords.back());
	angle_helper->clearAngles();
	if (rectangular_stepping)
		angle_helper->addAnglesDeg(angle * 180 / M_PI, 45);
	else
		angle_helper->addDefaultAnglesDeg(angle * 180 / M_PI);
}
Exemplo n.º 6
0
void DrawPathTool::startFollowing(SnappingToolHelperSnapInfo& snap_info, const MapCoord& snap_coord)
{
	following = true;
	follow_object = snap_info.object->asPath();
	create_segment = false;
	
	if (snap_info.type == SnappingToolHelper::ObjectCorners)
		follow_helper->startFollowingFromCoord(follow_object, snap_info.coord_index);
	else // if (snap_info.type == SnappingToolHelper::ObjectPaths)
		follow_helper->startFollowingFromPathCoord(follow_object, snap_info.path_coord);
	
	if (path_has_preview_point)
		preview_path->setCoordinate(preview_path->getCoordinateCount() - 1, snap_coord);
	else
		preview_path->addCoordinate(snap_coord);
	path_has_preview_point = false;
	previous_point_is_curve_point = false;
	updatePreviewPath();
	follow_start_index = preview_path->getCoordinateCount() - 1;
}
Exemplo n.º 7
0
void DrawFreehandTool::updatePath()
{
	float length_threshold_sq = 0.06f*0.06f; // minimum point distance in mm
	
	if (!dragging)
	{
		preview_path->clearCoordinates();
		preview_path->addCoordinate(MapCoord(cur_pos_map));
	}
	else
	{
		if (last_pos_map.distanceSquaredTo(cur_pos_map) < length_threshold_sq)
			return;
		preview_path->addCoordinate(MapCoord(cur_pos_map));
	}
	last_pos_map = cur_pos_map;
	
	updatePreviewPath();
	setDirtyRect();
}
Exemplo n.º 8
0
void DrawPathTool::undoLastPoint()
{
	Q_ASSERT(editingInProgress());
	
	if (preview_path->getCoordinateCount() <= (preview_path->parts().front().isClosed() ? 3 : (path_has_preview_point ? 2 : 1)))
	{
		abortDrawing();
		return;
	}
	
	auto& part = preview_path->parts().back();
	auto last_index = part.last_index;
	auto prev_coord_index = part.prevCoordIndex(part.last_index);
	auto prev_coord = preview_path->getCoordinate(prev_coord_index);
	
	// Pre-undo preparation
	if (path_has_preview_point)
	{
		if (prev_coord.isCurveStart())
		{
			// Undo just the preview point
			path_has_preview_point = false;
		}
		else
		{
			// Remove the preview point from a straight edge, preparing for re-adding.
			Q_ASSERT(!previous_point_is_curve_point);
			
			preview_path->deleteCoordinate(last_index, false);
			last_index = prev_coord_index;
			prev_coord_index = part.prevCoordIndex(part.last_index);
			prev_coord = preview_path->getCoordinate(prev_coord_index);
			
			path_has_preview_point = !prev_coord.isCurveStart();
		}
	}
	
	if (prev_coord.isCurveStart())
	{
		// Removing last point of a curve, no re-adding of preview point.
		MapCoord prev_drag = preview_path->getCoordinate(prev_coord_index+1);
		previous_point_direction = -atan2(prev_drag.x() - prev_coord.x(), prev_coord.y() - prev_drag.y());
		previous_pos_map = MapCoordF(prev_coord);
		previous_drag_map = MapCoordF((prev_coord.x() + prev_drag.x()) / 2, (prev_coord.y() + prev_drag.y()) / 2);
		previous_point_is_curve_point = true;
		path_has_preview_point = false;
	}
	else if (!path_has_preview_point)
	{
		// Removing last point from a straight edge, no re-adding of preview point.
		previous_point_is_curve_point = false;
	}
	
	// Actually delete the last point of the edge.
	preview_path->deleteCoordinate(last_index, false);
	if (preview_path->getRawCoordinateVector().empty())
	{
		// Re-add first point.
		prev_coord.setCurveStart(false);
		preview_path->addCoordinate(prev_coord);
	}
	
	// Post-undo
	if (path_has_preview_point)
	{
		// Re-add preview point.
		preview_path->addCoordinate(MapCoord(cur_pos_map));
	}
	else if (previous_point_is_curve_point && dragging)
	{
		cur_pos = click_pos;
		cur_pos_map = click_pos_map;
	}
	
	dragging = false;
	
	updateHover();
	updatePreviewPath();
	updateAngleHelper();
	updateDirtyRect();
}
Exemplo n.º 9
0
bool DrawPathTool::mouseReleaseEvent(QMouseEvent* event, MapCoordF map_coord, MapWidget* widget)
{
	if (!isDrawingButton(event->button()))
		return false;

	left_mouse_down = false;
	
	if (picking_angle)
	{
		picking_angle = false;
		picked_angle = pickAngle(map_coord, widget);
		return true;
	}
	else if (!editingInProgress())
	{
		return false;
	}
	
	if (following)
	{
		finishFollowing();
		if ((event->button() == Qt::RightButton) && drawOnRightClickEnabled())
			finishDrawing();
		return true;
	}
	
	if (!create_segment)
		return true;
	
	if (previous_point_is_curve_point && !dragging && !create_spline_corner)
	{
		// The new point has not been added yet
		MapCoord coord;
		if (shift_pressed)
		{
			coord = snap_helper->snapToObject(map_coord, widget);
		}
		else if (angle_helper->isActive())
		{
			QPointF constrained_pos;
			angle_helper->getConstrainedCursorPositions(map_coord, constrained_pos_map, constrained_pos, widget);
			coord = MapCoord(constrained_pos_map);
		}
		else
		{
			coord = MapCoord(map_coord);
		}
		
		if (draw_dash_points)
			coord.setDashPoint(true);
		preview_path->addCoordinate(coord);
		updatePreviewPath();
		updateDirtyRect();
	}
	
	previous_point_is_curve_point = dragging;
	if (previous_point_is_curve_point)
	{
		QPointF constrained_pos;
		angle_helper->getConstrainedCursorPositions(map_coord, constrained_pos_map, constrained_pos, widget);
		
		previous_pos_map = click_pos_map;
		previous_drag_map = constrained_pos_map;
		previous_point_direction = calculateRotation(constrained_pos.toPoint(), constrained_pos_map);
	}
	
	updateAngleHelper();
	
	create_spline_corner = false;
	path_has_preview_point = false;
	dragging = false;
	
	if ((event->button() == Qt::RightButton) && drawOnRightClickEnabled())
		finishDrawing();
	return true;
}
Exemplo n.º 10
0
bool DrawPathTool::mousePressEvent(QMouseEvent* event, MapCoordF map_coord, MapWidget* widget)
{
	cur_map_widget = widget;
	created_point_at_last_mouse_press = false;
	
	if (editingInProgress() &&
		((event->button() == Qt::RightButton) &&
		!drawOnRightClickEnabled()))
	{
		finishDrawing();
		return true;
	}
	else if (editingInProgress() &&
		((event->button() == Qt::RightButton && event->buttons() & Qt::LeftButton) ||
		 (event->button() == Qt::LeftButton && event->buttons() & Qt::RightButton)))
	{
		if (!previous_point_is_curve_point)
			undoLastPoint();
		if (editingInProgress())
			finishDrawing();
		return true;
	}
	else if (isDrawingButton(event->button()))
	{
		dragging = false;
		bool start_appending = false;
		if (shift_pressed)
		{
			SnappingToolHelperSnapInfo snap_info;
			MapCoord snap_coord = snap_helper->snapToObject(map_coord, widget, &snap_info);
			click_pos_map = MapCoordF(snap_coord);
			cur_pos_map = click_pos_map;
			click_pos = widget->mapToViewport(click_pos_map).toPoint();
			
			// Check for following and appending
			if (!is_helper_tool)
			{
				if (!editingInProgress())
				{
					if (snap_info.type == SnappingToolHelper::ObjectCorners &&
						(snap_info.coord_index == 0 || snap_info.coord_index == snap_info.object->asPath()->getCoordinateCount() - 1) &&
						snap_info.object->getSymbol() == editor->activeSymbol())
					{
						// Appending to another path
						start_appending = true;
						startAppending(snap_info);
					}
					
					// Setup angle helper
					if (snap_helper->snapToDirection(map_coord, widget, angle_helper.data()))
						picked_angle = true;
				}
				else if (editingInProgress() &&
						 (snap_info.type == SnappingToolHelper::ObjectCorners || snap_info.type == SnappingToolHelper::ObjectPaths) &&
						 snap_info.object->getType() == Object::Path)
				{
					// Start following another path
					startFollowing(snap_info, snap_coord);
					return true;
				}
			}
		}
		else if (!editingInProgress() && ctrl_pressed)
		{
			// Start picking direction of an existing object
			picking_angle = true;
			pickAngle(map_coord, widget);
			return true;
		}
		else
		{
			click_pos = event->pos();
			click_pos_map = map_coord;
			cur_pos_map = map_coord;
		}
		
		if (!editingInProgress())
		{
			// Start a new path
			startDrawing();
			angle_helper->setCenter(click_pos_map);
			updateSnapHelper();
			
			path_has_preview_point = false;
			previous_point_is_curve_point = false;
			appending = start_appending;
		}
		else
		{
			if (!shift_pressed)
				angle_helper->getConstrainedCursorPosMap(click_pos_map, click_pos_map);
			cur_pos_map = click_pos_map;
		}

		// Set path point
		auto coord = MapCoord { click_pos_map };
		if (draw_dash_points)
			coord.setDashPoint(true);
		
		if (preview_path->getCoordinateCount() > 0 && picked_angle)
			picked_angle = false;
		if (previous_point_is_curve_point)
		{
			// Do nothing yet, wait until the user drags or releases the mouse button
		}
		else if (path_has_preview_point)
		{
			preview_path->setCoordinate(preview_path->getCoordinateCount() - 1, coord);
			updateAngleHelper();
			created_point_at_last_mouse_press = true;
		}
		else
		{
			if (preview_path->getCoordinateCount() == 0 || !preview_path->getCoordinate(preview_path->getCoordinateCount() - 1).isPositionEqualTo(coord))
			{
				preview_path->addCoordinate(coord);
				updatePreviewPath();
				if (!start_appending)
					updateAngleHelper();
				created_point_at_last_mouse_press = true;
			}
		}
		
		path_has_preview_point = false;
		
		create_segment = true;
		updateDirtyRect();
		updateStatusText();
		return true;
	}
	
	return false;
}
Exemplo n.º 11
0
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();
}