Пример #1
0
void MapPart::findObjectsAt(
        MapCoordF coord,
        float tolerance,
        bool treat_areas_as_paths,
        bool extended_selection,
        bool include_hidden_objects,
        bool include_protected_objects,
        SelectionInfoVector& out ) const
{
	for (Object* object : objects)
	{
		if (!include_hidden_objects && object->getSymbol()->isHidden())
			continue;
		if (!include_protected_objects && object->getSymbol()->isProtected())
			continue;
		
		object->update();
		int selected_type = object->isPointOnObject(coord, tolerance, treat_areas_as_paths, extended_selection);
		if (selected_type != (int)Symbol::NoSymbol)
			out.emplace_back(selected_type, object);
	}
}
Пример #2
0
MapCoord SnappingToolHelper::snapToObject(MapCoordF position, MapWidget* widget, SnappingToolHelperSnapInfo* info, Object* exclude_object, float snap_distance)
{
	if (snap_distance < 0)
		snap_distance = 0.001f * widget->getMapView()->pixelToLength(Settings::getInstance().getMapEditorSnapDistancePx());
	float closest_distance_sq = snap_distance * snap_distance;
	auto result_position = MapCoord { position };
	SnappingToolHelperSnapInfo result_info;
	result_info.type = NoSnapping;
	result_info.object = NULL;
	result_info.coord_index = -1;
	result_info.path_coord.pos = MapCoordF(0, 0);
	result_info.path_coord.index = -1;
	result_info.path_coord.clen = -1;
	result_info.path_coord.param = -1;
	
	if (filter & (ObjectCorners | ObjectPaths))
	{
		// Find map objects at the given position
		SelectionInfoVector objects;
		map->findAllObjectsAt(position, snap_distance, true, false, false, true, objects);
		
		// Find closest snap spot from map objects
		for (SelectionInfoVector::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it)
		{
			Object* object = it->second;
			if (object == exclude_object)
				continue;
			
			float distance_sq;
			if (object->getType() == Object::Point && filter & ObjectCorners)
			{
				PointObject* point = object->asPoint();
				distance_sq = point->getCoordF().distanceSquaredTo(position);
				if (distance_sq < closest_distance_sq)
				{
					closest_distance_sq = distance_sq;
					result_position = point->getCoord();
					result_info.type = ObjectCorners;
					result_info.object = object;
					result_info.coord_index = 0;
				}
			}
			else if (object->getType() == Object::Path)
			{
				PathObject* path = object->asPath();
				if (filter & ObjectPaths)
				{
					PathCoord path_coord;
					path->calcClosestPointOnPath(position, distance_sq, path_coord);
					if (distance_sq < closest_distance_sq)
					{
						closest_distance_sq = distance_sq;
						result_position = MapCoord(path_coord.pos);
						result_info.object = object;
						if (path_coord.param == 0.0)
						{
							result_info.type = ObjectCorners;
							result_info.coord_index = path_coord.index;
						}
						else
						{
							result_info.type = ObjectPaths;
							result_info.coord_index = -1;
							result_info.path_coord = path_coord;
						}
					}
				}
				else
				{
					MapCoordVector::size_type index;
					path->calcClosestCoordinate(position, distance_sq, index);
					if (distance_sq < closest_distance_sq)
					{
						closest_distance_sq = distance_sq;
						result_position = path->getCoordinate(index);
						result_info.type = ObjectCorners;
						result_info.object = object;
						result_info.coord_index = index;
					}
				}
			}
			else if (object->getType() == Object::Text)
			{
				// No snapping to texts
				continue;
			}
		}
	}
	
	// Find closest grid snap position
	if ((filter & GridCorners) && widget->getMapView()->isGridVisible() &&
		map->getGrid().isSnappingEnabled() && map->getGrid().getDisplayMode() == MapGrid::AllLines)
	{
		MapCoordF closest_grid_point = map->getGrid().getClosestPointOnGrid(position, map);
		float distance_sq = closest_grid_point.distanceSquaredTo(position);
		if (distance_sq < closest_distance_sq)
		{
			closest_distance_sq = distance_sq;
			result_position = MapCoord(closest_grid_point);
			result_info.type = GridCorners;
			result_info.object = NULL;
			result_info.coord_index = -1;
		}
	}
	
	// Return
	if (snap_mark != result_position || snapped_type != result_info.type)
	{
		snap_mark = result_position;
		snapped_type = result_info.type;
		emit displayChanged();
	}
	
	if (info != NULL)
		*info = result_info;
	return result_position;
}
Пример #3
0
bool ObjectSelector::selectAt(MapCoordF position, double tolerance, bool toggle)
{
	bool selection_changed;
	
	bool single_object_selected = map->getNumSelectedObjects() == 1;
	Object* single_selected_object = nullptr;
	if (single_object_selected)
		single_selected_object = *map->selectedObjectsBegin();
	
	// Clicked - get objects below cursor
	SelectionInfoVector objects;
	map->findObjectsAt(position, 0.001f * tolerance, false, false, false, false, objects);
	if (objects.empty())
		map->findObjectsAt(position, 0.001f * 1.5f * tolerance, false, true, false, false, objects);
	
	// Selection logic, trying to select the most relevant object(s)
	if (!toggle || map->getNumSelectedObjects() == 0)
	{
		if (objects.empty())
		{
			// Clicked on empty space, deselect everything
			selection_changed = map->getNumSelectedObjects() > 0;
			last_results.clear();
			map->clearObjectSelection(true);
		}
		else if (!last_results.empty() && selectionInfosEqual(objects, last_results))
		{
			// If this result is the same as last time, select next object
			next_object_to_select = next_object_to_select % last_results_ordered.size();
			
			map->clearObjectSelection(false);
			map->addObjectToSelection(last_results_ordered[next_object_to_select].second, true);
			selection_changed = true;
			
			++next_object_to_select;
		}
		else
		{
			// Results different - select object with highest priority, if it is not the same as before
			last_results = objects;
			std::sort(objects.begin(), objects.end(), sortObjects);
			last_results_ordered = std::move(objects);
			next_object_to_select = 1;
			
			map->clearObjectSelection(false);
			if (single_selected_object == last_results_ordered.begin()->second)
			{
				next_object_to_select = next_object_to_select % last_results_ordered.size();
				map->addObjectToSelection(last_results_ordered[next_object_to_select].second, true);
				++next_object_to_select;
			}
			else
				map->addObjectToSelection(last_results_ordered.begin()->second, true);
			
			selection_changed = true;
		}
	}
	else
	{
		// Shift held and something is already selected
		if (objects.empty())
		{
			// do nothing
			selection_changed = false;
		}
		else if (!last_results.empty() && selectionInfosEqual(objects, last_results))
		{
			// Toggle last selected object - must work the same way, regardless if other objects are selected or not
			next_object_to_select = next_object_to_select % last_results_ordered.size();
			
			if (map->toggleObjectSelection(last_results_ordered[next_object_to_select].second, true) == false)
				++next_object_to_select;	// only advance if object has been deselected
			selection_changed = true;
		}
		else
		{
			// Toggle selection of highest priority object
			last_results = objects;
			std::sort(objects.begin(), objects.end(), sortObjects);
			last_results_ordered = std::move(objects);
			
			map->toggleObjectSelection(last_results_ordered.begin()->second, true);
			selection_changed = true;
		}
	}
	
	return selection_changed;
}
Пример #4
0
bool ObjectSelector::selectionInfosEqual(const SelectionInfoVector& a, const SelectionInfoVector& b)
{
	return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
}