コード例 #1
0
void ObjectQuery::selectMatchingObjects(Map* map, MapEditorController* controller) const
{
	bool had_selection = !map->selectedObjects().empty();
	map->clearObjectSelection(false);

	// Lambda to add objects to the selection
	auto select_object = [map](Object* const object, MapPart*, int)
	{
		map->addObjectToSelection(object, false);
		return false; // applyOnMatchingObjects tells us if this op fails, so if we fail we made a selection
	};

	MapPart *part = map->getCurrentPart();

	// This reports failure if we made a selection
	auto object_selected = !part->applyOnMatchingObjects(select_object, *this);

	if (object_selected || had_selection)
		map->emitSelectionChanged();

	if (object_selected)
	{
		auto current_tool = controller->getTool();
		if (current_tool && current_tool->isDrawTool())
			controller->setEditTool();
	}
}
コード例 #2
0
ファイル: object_undo.cpp プロジェクト: FEK10/mapper
UndoStep* AddObjectsUndoStep::undo()
{
	int const part_index = getPartIndex();
	
	DeleteObjectsUndoStep* undo_step = new DeleteObjectsUndoStep(map);
	undo_step->setPartIndex(part_index);
	
	// Make sure to add the objects in the right order so the other objects' indices stay valid
	std::vector< std::pair<int, int> > order;	// index into affected_objects & objects, object index
	order.resize(modified_objects.size());
	for (int i = 0; i < (int)modified_objects.size(); ++i)
		order[i] = std::pair<int, int>(i, modified_objects[i]);
	std::sort(order.begin(), order.end(), sortOrder);
	
	MapPart* part = map->getPart(part_index);
	int size = (int)objects.size();
	for (int i = 0; i < size; ++i)
	{
		undo_step->addObject(modified_objects[order[i].first]);
		part->addObject(objects[order[i].first], order[i].second);
	}
	
	undone = true;
	return undo_step;
}
コード例 #3
0
ファイル: Level.cpp プロジェクト: Codibri/HardrockHoliday
void  Level::attachAllMapPartsToScene(Vektoria::CScene* scene){

	for (int i = 0; i < mMapParts.size(); i++){
		MapPart* p = mMapParts[i];
		p->getPlacement()->TranslateZ(-MapPart::MAP_PART_SIZE * i);
		scene->AddPlacement(p->getPlacement());
	}

}
コード例 #4
0
ファイル: tool_cutout.cpp プロジェクト: 999999333/mapper
	UndoStep* finish()
	{
		MapPart* part = map->getCurrentPart();
		
		map->clearObjectSelection(false);
		add_step->removeContainedObjects(false);
		for (size_t i = 0; i < new_objects.size(); ++i)
		{
			Object* object = new_objects[i];
			map->addObject(object);
		}
		// Do not merge this loop into the upper one;
		// theoretically undo step indices could be wrong this way.
		for (size_t i = 0; i < new_objects.size(); ++i)
		{
			Object* object = new_objects[i];
			delete_step->addObject(part->findObjectIndex(object));
		}
		map->emitSelectionChanged();
		
		// Return undo step
		if (delete_step->isEmpty())
		{
			delete delete_step;
			if (add_step->isEmpty())
			{
				delete add_step;
				return NULL;
			}
			else
				return add_step;
		}
		else
		{
			if (add_step->isEmpty())
			{
				delete add_step;
				return delete_step;	
			}
			else
			{
				CombinedUndoStep* combined_step = new CombinedUndoStep(map);
				combined_step->push(add_step);
				combined_step->push(delete_step);
				return combined_step;
			}
		}
	}
コード例 #5
0
ファイル: tool_boolean.cpp プロジェクト: kshji/mapper
bool BooleanTool::executeForObjects(PathObject* subject, PathObjects& in_objects, PathObjects& out_objects, CombinedUndoStep& undo_step)
{
	if (!executeForObjects(subject, in_objects, out_objects))
	{
		Q_ASSERT(out_objects.size() == 0);
		return false; // in release build
	}
	
	// Add original objects to undo step, and remove them from map.
	QScopedPointer<AddObjectsUndoStep> add_step(new AddObjectsUndoStep(map));
	for (PathObject* object : in_objects)
	{
		if (op != Difference || object == subject)
		{
			add_step->addObject(object, object);
		}
	}
	// Keep as separate loop to get the correct index in the previous loop
	for (PathObject* object : in_objects)
	{
		if (op != Difference || object == subject)
		{
			map->removeObjectFromSelection(object, false);
			map->getCurrentPart()->deleteObject(object, true);
			object->setMap(map); // necessary so objects are saved correctly
		}
	}
	
	// Add resulting objects to map, and create delete step for them
	QScopedPointer<DeleteObjectsUndoStep> delete_step(new DeleteObjectsUndoStep(map));
	MapPart* part = map->getCurrentPart();
	for (PathObject* object : out_objects)
	{
		map->addObject(object);
		map->addObjectToSelection(object, false);
	}
	// Keep as separate loop to get the correct index in the previous loop
	for (PathObject* object : out_objects)
	{
		delete_step->addObject(part->findObjectIndex(object));
	}
	
	undo_step.push(add_step.take());
	undo_step.push(delete_step.take());
	return true;
}
コード例 #6
0
ファイル: object_undo.cpp プロジェクト: FEK10/mapper
void AddObjectsUndoStep::removeContainedObjects(bool emit_selection_changed)
{
	MapPart* part = map->getPart(getPartIndex());
	int size = (int)objects.size();
	bool object_deselected = false;
	for (int i = 0; i < size; ++i)
	{
		if (map->isObjectSelected(objects[i]))
		{
			map->removeObjectFromSelection(objects[i], false);
			object_deselected = true;
		}
		part->deleteObject(objects[i], true);
		map->setObjectsDirty();
	}
	if (object_deselected && emit_selection_changed)
		map->emitSelectionChanged();
}
コード例 #7
0
ファイル: object_undo.cpp プロジェクト: FEK10/mapper
UndoStep* ReplaceObjectsUndoStep::undo()
{
	int const part_index = getPartIndex();
	
	ReplaceObjectsUndoStep* undo_step = new ReplaceObjectsUndoStep(map);
	undo_step->setPartIndex(part_index);
	
	MapPart* part = map->getPart(part_index);
	std::size_t size = objects.size();
	for (std::size_t i = 0; i < size; ++i)
	{
		undo_step->addObject(modified_objects[i], part->getObject(modified_objects[i]));
		part->setObject(objects[i], modified_objects[i], false);
	}
	
	undone = true;
	return undo_step;
}
コード例 #8
0
ファイル: object_undo.cpp プロジェクト: FEK10/mapper
UndoStep* SwitchDashesUndoStep::undo()
{
	int const part_index = getPartIndex();
	
	SwitchDashesUndoStep* undo_step = new SwitchDashesUndoStep(map);
	undo_step->setPartIndex(part_index);
	
	MapPart* part = map->getPart(part_index);
	for (ObjectList::iterator it = modified_objects.begin(), end = modified_objects.end(); it != end; ++it)
	{
		PathObject* object = reinterpret_cast<PathObject*>(part->getObject(*it));
		object->reverse();
		object->update();
		
		undo_step->addObject(*it);
	}
	
	return undo_step;
}
コード例 #9
0
ファイル: object_undo.cpp プロジェクト: FEK10/mapper
UndoStep* SwitchSymbolUndoStep::undo()
{
	int const part_index = getPartIndex();
	
	SwitchSymbolUndoStep* undo_step = new SwitchSymbolUndoStep(map);
	undo_step->setPartIndex(part_index);
	
	MapPart* part = map->getPart(part_index);
	int size = (int)modified_objects.size();
	for (int i = 0; i < size; ++i)
	{
		Object* object = part->getObject(modified_objects[i]);
		undo_step->addObject(modified_objects[i], object->getSymbol());
		bool ok = object->setSymbol(target_symbols[i], false);
		Q_ASSERT(ok);
		Q_UNUSED(ok);
	}
	
	return undo_step;
}
コード例 #10
0
ファイル: object_undo.cpp プロジェクト: FEK10/mapper
UndoStep* DeleteObjectsUndoStep::undo()
{
	int const part_index = getPartIndex();
	
	AddObjectsUndoStep* undo_step = new AddObjectsUndoStep(map);
	undo_step->setPartIndex(part_index);
	
	// Make sure to delete the objects in the right order so the other objects' indices stay valid
	std::sort(modified_objects.begin(), modified_objects.end(), std::greater<int>());
	
	MapPart* part = map->getPart(part_index);
	int size = (int)modified_objects.size();
	for (int i = 0; i < size; ++i)
	{
		undo_step->addObject(modified_objects[i], part->getObject(modified_objects[i]));
		part->deleteObject(modified_objects[i], true);
	}
	
	return undo_step;
}
コード例 #11
0
ファイル: file_format_native.cpp プロジェクト: sembruk/mapper
void NativeFileImport::import(bool load_symbols_only)
{
    addWarning(Importer::tr("This file uses an obsolete format. "
                            "Support for this format is to be removed from this program soon. "
                            "To be able to open the file in the future, save it again."));

    MapCoord::boundsOffset().reset(true);

    char buffer[4];
    stream->read(buffer, 4); // read the magic

    int version;
    stream->read((char*)&version, sizeof(int));
    if (version < 0)
    {
        addWarning(Importer::tr("Invalid file format version."));
    }
    else if (version < NativeFileFormat::least_supported_file_format_version)
    {
        throw FileFormatException(Importer::tr("Unsupported old file format version. Please use an older program version to load and update the file."));
    }
    else if (version > NativeFileFormat::current_file_format_version)
    {
        throw FileFormatException(Importer::tr("Unsupported new file format version. Some map features will not be loaded or saved by this version of the program. Consider updating."));
    }

    if (version <= 16)
	{
		Georeferencing georef;
		stream->read((char*)&georef.scale_denominator, sizeof(int));
		
		if (version >= 15)
			loadString(stream, map->map_notes);
		
		bool gps_projection_params_set; // obsolete
		stream->read((char*)&gps_projection_params_set, sizeof(bool));
		GPSProjectionParameters gps_projection_parameters; // obsolete
		stream->read((char*)&gps_projection_parameters, sizeof(GPSProjectionParameters));
		if (gps_projection_params_set)
		{
			LatLon ref_point = LatLon::fromRadiant(gps_projection_parameters.center_latitude, gps_projection_parameters.center_longitude);
			georef.setGeographicRefPoint(ref_point);
		}
		*map->georeferencing = georef;
	}
	else if (version >= 17)
	{
		loadString(stream, map->map_notes);
		
		Georeferencing georef;
		stream->read((char*)&georef.scale_denominator, sizeof(int));
		double value;
		if (version >= 18)
		{
			stream->read((char*)&value, sizeof(double));
			georef.declination = Georeferencing::roundDeclination(value);
		}
		stream->read((char*)&value, sizeof(double));
		georef.grivation = Georeferencing::roundDeclination(value);
		georef.grivation_error = value - georef.grivation;
		
		double x,y;
		stream->read((char*)&x, sizeof(double));
		stream->read((char*)&y, sizeof(double));
		georef.map_ref_point = MapCoord(x,y);
		stream->read((char*)&x, sizeof(double));
		stream->read((char*)&y, sizeof(double));
		georef.projected_ref_point = QPointF(x,y);
		loadString(stream, georef.projected_crs_id);
		loadString(stream, georef.projected_crs_spec);
		stream->read((char*)&y, sizeof(double));
		stream->read((char*)&x, sizeof(double));
		georef.geographic_ref_point = LatLon::fromRadiant(y, x); 
		QString geographic_crs_id, geographic_crs_spec;
		loadString(stream, geographic_crs_id);   // reserved for geographic crs id
		loadString(stream, geographic_crs_spec); // reserved for full geographic crs specification
		if (geographic_crs_spec != Georeferencing::geographic_crs_spec)
		{
			addWarning(
			  Importer::tr("The geographic coordinate reference system of the map was \"%1\". This CRS is not supported. Using \"%2\".").
			  arg(geographic_crs_spec).
			  arg(Georeferencing::geographic_crs_spec)
			);
		}
		if (version <= 17)
			georef.initDeclination();
		// Correctly set georeferencing state
		georef.setProjectedCRS(georef.projected_crs_id, georef.projected_crs_spec);
		*map->georeferencing = georef;
	}
	
	if (version >= 24)
		map->setGrid(MapGrid().load(stream, version));
	
	map->renderable_options = Symbol::RenderNormal;
	if (version >= 25)
	{
		bool area_hatching_enabled, baseline_view_enabled;
		stream->read((char*)&area_hatching_enabled, sizeof(bool));
		stream->read((char*)&baseline_view_enabled, sizeof(bool));
		if (area_hatching_enabled)
			map->renderable_options |= Symbol::RenderAreasHatched;
		if (baseline_view_enabled)
			map->renderable_options |= Symbol::RenderBaselines;
	}
	
	if (version >= 6)
	{
		bool print_params_set;
		stream->read((char*)&print_params_set, sizeof(bool));
		if (print_params_set)
		{
			MapPrinterConfig printer_config(*map);
			stream->read((char*)&printer_config.page_format.orientation, sizeof(int));
			stream->read((char*)&printer_config.page_format.paper_size, sizeof(int));
			
			float resolution;
			stream->read((char*)&resolution, sizeof(float));
			printer_config.options.resolution = qRound(resolution);
			stream->read((char*)&printer_config.options.show_templates, sizeof(bool));
			if (version >= 24)
				stream->read((char*)&printer_config.options.show_grid, sizeof(bool));
			else
				printer_config.options.show_grid = false;
			
			stream->read((char*)&printer_config.center_print_area, sizeof(bool));
			
			float print_area_left, print_area_top, print_area_width, print_area_height;
			stream->read((char*)&print_area_left, sizeof(float));
			stream->read((char*)&print_area_top, sizeof(float));
			stream->read((char*)&print_area_width, sizeof(float));
			stream->read((char*)&print_area_height, sizeof(float));
			printer_config.print_area = QRectF(print_area_left, print_area_top, print_area_width, print_area_height);
			
			if (version >= 26)
			{
				bool print_different_scale_enabled;
				stream->read((char*)&print_different_scale_enabled, sizeof(bool));
				stream->read((char*)&printer_config.options.scale, sizeof(int));
				if (!print_different_scale_enabled)
					printer_config.options.scale = map->getScaleDenominator();
			}
			map->setPrinterConfig(printer_config);
		}
	}
	
    if (version >= 16)
	{
		stream->read((char*)&map->image_template_use_meters_per_pixel, sizeof(bool));
		stream->read((char*)&map->image_template_meters_per_pixel, sizeof(double));
		stream->read((char*)&map->image_template_dpi, sizeof(double));
		stream->read((char*)&map->image_template_scale, sizeof(double));
	}

    // Load colors
    int num_colors;
    stream->read((char*)&num_colors, sizeof(int));
    map->color_set->colors.resize(num_colors);

    for (int i = 0; i < num_colors; ++i)
    {
        int priority;
        stream->read((char*)&priority, sizeof(int));
        MapColor* color = new MapColor(priority);

        MapColorCmyk cmyk;
        stream->read((char*)&cmyk.c, sizeof(float));
        stream->read((char*)&cmyk.m, sizeof(float));
        stream->read((char*)&cmyk.y, sizeof(float));
        stream->read((char*)&cmyk.k, sizeof(float));
        color->setCmyk(cmyk);
        float opacity;
        stream->read((char*)&opacity, sizeof(float));
        color->setOpacity(opacity);

        QString name;
        loadString(stream, name);
        color->setName(name);

        map->color_set->colors[i] = color;
    }

    // Load symbols
    int num_symbols;
    stream->read((char*)&num_symbols, sizeof(int));
    map->symbols.resize(num_symbols);

    for (int i = 0; i < num_symbols; ++i)
    {
        QScopedValueRollback<MapCoord::BoundsOffset> offset { MapCoord::boundsOffset() };
        MapCoord::boundsOffset().reset(false);

        int symbol_type;
        stream->read((char*)&symbol_type, sizeof(int));

        Symbol* symbol = Symbol::getSymbolForType(static_cast<Symbol::Type>(symbol_type));
        if (!symbol)
        {
            throw FileFormatException(Importer::tr("Error while loading a symbol with type %2.").arg(symbol_type));
        }

        if (!symbol->load(stream, version, map))
        {
            throw FileFormatException(Importer::tr("Error while loading a symbol."));
        }
        map->symbols[i] = symbol;
    }

    if (!load_symbols_only)
	{
		// Load templates
		stream->read((char*)&map->first_front_template, sizeof(int));

		int num_templates;
		stream->read((char*)&num_templates, sizeof(int));
		map->templates.resize(num_templates);

		for (int i = 0; i < num_templates; ++i)
		{
			QString path;
			loadString(stream, path);
			auto temp = Template::templateForFile(path, map);
			if (!temp)
				temp.reset(new TemplateImage(path, map)); // fallback
			
			if (version >= 27)
			{
				loadString(stream, path);
				temp->setTemplateRelativePath(path);
			}
			
			temp->loadTemplateConfiguration(stream, version);

			map->templates[i] = temp.release();
		}
		
		if (version >= 28)
		{
			int num_closed_templates;
			stream->read((char*)&num_closed_templates, sizeof(int));
			map->closed_templates.resize(num_closed_templates);
			
			for (int i = 0; i < num_closed_templates; ++i)
			{
				QString path;
				loadString(stream, path);
				auto temp = Template::templateForFile(path, map);
				if (!temp)
					temp.reset(new TemplateImage(path, map)); // fallback
				
				loadString(stream, path);
				temp->setTemplateRelativePath(path);
				
				temp->loadTemplateConfiguration(stream, version);
				
				map->closed_templates[i] = temp.release();
			}
		}

		// Restore widgets and views
		if (view)
		{
			view->load(stream, version);
		}
		else
		{
			MapView tmp{ map };
			tmp.load(stream, version);
		}

		// Load undo steps
		if (version >= 7)
		{
			if (!map->undoManager().load(stream, version))
			{
				throw FileFormatException(Importer::tr("Error while loading undo steps."));
			}
		}

		// Load parts
		stream->read((char*)&map->current_part_index, sizeof(int));

		int num_parts;
		if (stream->read((char*)&num_parts, sizeof(int)) < (int)sizeof(int))
		{
			throw FileFormatException(Importer::tr("Error while reading map part count."));
		}
		delete map->parts[0];
		map->parts.resize(num_parts);

		for (int i = 0; i < num_parts; ++i)
		{
			MapPart* part = new MapPart({}, map);
			if (!part->load(stream, version, map))
			{
				throw FileFormatException(Importer::tr("Error while loading map part %2.").arg(i+1));
			}
			map->parts[i] = part;
		}
	}
	
	emit map->currentMapPartIndexChanged(map->current_part_index);
	emit map->currentMapPartChanged(map->getPart(map->current_part_index));
}
コード例 #12
0
ファイル: file_import_export.cpp プロジェクト: kshji/mapper
void Importer::doImport(bool load_symbols_only, const QString& map_path)
{
	import(load_symbols_only);
	
	// Object post processing:
	// - make sure that there is no object without symbol
	// - make sure that all area-only path objects are closed
	// - make sure that there are no special points in wrong places (e.g. curve starts inside curves)
	for (int p = 0; p < map->getNumParts(); ++p)
	{
		MapPart* part = map->getPart(p);
		for (int o = 0; o < part->getNumObjects(); ++o)
		{
			Object* object = part->getObject(o);
			if (object->getSymbol() == NULL)
			{
				addWarning(Importer::tr("Found an object without symbol."));
				if (object->getType() == Object::Point)
					object->setSymbol(map->getUndefinedPoint(), true);
				else if (object->getType() == Object::Path)
					object->setSymbol(map->getUndefinedLine(), true);
				else
				{
					// There is no undefined symbol for this type of object, delete the object
					part->deleteObject(o, false);
					--o;
					continue;
				}
			}
			
			if (object->getType() == Object::Path)
			{
				PathObject* path = object->asPath();
				Symbol::Type contained_types = path->getSymbol()->getContainedTypes();
				if (contained_types & Symbol::Area && !(contained_types & Symbol::Line))
					path->closeAllParts();
				
				for (MapCoordVector::size_type i = 0; i < path->getCoordinateCount(); ++i)
				{
					if (path->getCoordinate(i).isCurveStart())
					{
						if (i+3 >= path->getCoordinateCount())
						{
							path->getCoordinate(i).setCurveStart(false);
							continue;
						}
						
						if (path->getCoordinate(i + 1).isClosePoint() || path->getCoordinate(i + 1).isHolePoint() ||
						    path->getCoordinate(i + 2).isClosePoint() || path->getCoordinate(i + 2).isHolePoint())
						{
							path->getCoordinate(i).setCurveStart(false);
							continue;
						}
						
						path->getCoordinate(i + 1).setCurveStart(false);
						path->getCoordinate(i + 1).setDashPoint(false);
						path->getCoordinate(i + 2).setCurveStart(false);
						path->getCoordinate(i + 2).setDashPoint(false);
						i += 2;
					}
					
					if (i > 0 && path->getCoordinate(i).isHolePoint())
					{
						if (path->getCoordinate(i-1).isHolePoint())
							path->deleteCoordinate(i, false);
					}
				}
			}
		}
	}
	
	// Symbol post processing
	for (int i = 0; i < map->getNumSymbols(); ++i)
	{
		if (!map->getSymbol(i)->loadFinished(map))
			throw FileFormatException(Importer::tr("Error during symbol post-processing."));
	}
	
	// Template loading: try to find all template files
	bool have_lost_template = false;
	for (int i = 0; i < map->getNumTemplates(); ++i)
	{
		Template* temp = map->getTemplate(i);
		
		bool loaded_from_template_dir = false;
		temp->tryToFindAndReloadTemplateFile(map_path, &loaded_from_template_dir);
		if (loaded_from_template_dir)
			addWarning(Importer::tr("Template \"%1\" has been loaded from the map's directory instead of the relative location to the map file where it was previously.").arg(temp->getTemplateFilename()));
		
		if (temp->getTemplateState() != Template::Loaded)
			have_lost_template = true;
	}
	if (have_lost_template)
	{
#if defined(Q_OS_ANDROID)
		addWarning(tr("At least one template file could not be found."));
#else
		addWarning(tr("At least one template file could not be found.") + " " +
		           tr("Click the red template name(s) in the Templates -> Template setup window to locate the template file name(s)."));
#endif
	}
}
コード例 #13
0
ファイル: template_track.cpp プロジェクト: 02JanDal/mapper
bool TemplateTrack::import(QWidget* dialog_parent)
{
	if (track.getNumWaypoints() == 0 && track.getNumSegments() == 0)
	{
		QMessageBox::critical(dialog_parent, tr("Error"), tr("The path is empty, there is nothing to import!"));
		return false;
	}
	
	const Track::ElementTags& tags = track.tags();
	DeleteObjectsUndoStep* undo_step = new DeleteObjectsUndoStep(map);
	MapPart* part = map->getCurrentPart();
	std::vector< Object* > result;
	
	map->clearObjectSelection(false);
	
	if (track.getNumWaypoints() > 0)
	{
		int res = QMessageBox::question(dialog_parent, tr("Question"), tr("Should the waypoints be imported as a line going through all points?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
		if (res == QMessageBox::No)
		{
			for (int i = 0; i < track.getNumWaypoints(); i++)
				result.push_back(importWaypoint(templateToMap(track.getWaypoint(i).map_coord), track.getWaypointName(i)));
		}
		else
		{
			PathObject* path = importPathStart();
			for (int i = 0; i < track.getNumWaypoints(); i++)
				path->addCoordinate(MapCoord(templateToMap(track.getWaypoint(i).map_coord)));
			importPathEnd(path);
			path->setTag(QStringLiteral("name"), QString{});
			result.push_back(path);
		}
	}
	
	int skipped_paths = 0;
	for (int i = 0; i < track.getNumSegments(); i++)
	{
		const int segment_size = track.getSegmentPointCount(i);
		if (segment_size == 0)
		{
			++skipped_paths;
			continue; // Don't create path without objects.
		}
		
		PathObject* path = importPathStart();
		QString name = track.getSegmentName(i);
		if (!tags[name].isEmpty())
		{
			path->setTags(tags[name]);
		}
		else
		{
			path->setTag(QStringLiteral("name"), name);
		}
		
		for (int j = 0; j < segment_size; j++)
		{
			const TrackPoint& track_point = track.getSegmentPoint(i, j);
			auto coord = MapCoord { templateToMap(track_point.map_coord) };
			if (track_point.is_curve_start && j < segment_size - 3)
				coord.setCurveStart(true);
			path->addCoordinate(coord);
		}
		if (track.getSegmentPoint(i, 0).gps_coord == track.getSegmentPoint(i, segment_size-1).gps_coord)
		{
			path->closeAllParts();
		}
		importPathEnd(path);
		result.push_back(path);
	}
	
	for (int i = 0; i < (int)result.size(); ++i) // keep as separate loop to get the correct (final) indices
		undo_step->addObject(part->findObjectIndex(result[i]));
	
	map->setObjectsDirty();
	map->push(undo_step);
	
	map->emitSelectionChanged();
	map->emitSelectionEdited();		// TODO: is this necessary here?
	
	if (skipped_paths)
	{
		QMessageBox::information(
		  dialog_parent,
		  tr("Import problems"),
		  tr("%n path object(s) could not be imported (reason: missing coordinates).", "", skipped_paths) );
	}
	
	return true;
}
コード例 #14
0
ファイル: tool_cut.cpp プロジェクト: aivarszo/mapper
void CutTool::pathFinished(PathObject* split_path)
{
	Map* map = this->map();
	
	// Get path endpoint and check if it is on the area boundary
	const MapCoordVector& path_coords = split_path->getRawCoordinateVector();
	MapCoord path_end = path_coords.at(path_coords.size() - 1);
	
	PathObject* edited_path = reinterpret_cast<PathObject*>(edit_object);
	PathCoord end_path_coord;
	float distance_sq;
	edited_path->calcClosestPointOnPath(MapCoordF(path_end), distance_sq, end_path_coord);
	
	float click_tolerance_map = 0.001 * edit_widget->getMapView()->pixelToLength(clickTolerance());
	if (distance_sq > click_tolerance_map*click_tolerance_map)
	{
		QMessageBox::warning(window(), tr("Error"), tr("The split line must end on the area boundary!"));
		pathAborted();
		return;
	}
	else if (drag_part_index != edited_path->findPartIndexForIndex(end_path_coord.index))
	{
		QMessageBox::warning(window(), tr("Error"), tr("Start and end of the split line are at different parts of the object!"));
		pathAborted();
		return;
	}
	else if (drag_start_len == end_path_coord.clen)
	{
		QMessageBox::warning(window(), tr("Error"), tr("Start and end of the split line are at the same position!"));
		pathAborted();
		return;
	}
	
	Q_ASSERT(split_path->parts().size() == 1);
	split_path->parts().front().setClosed(false);
	split_path->setCoordinate(split_path->getCoordinateCount() - 1, MapCoord(end_path_coord.pos));
	
	// Do the splitting
	const double split_threshold = 0.01;
	
	MapPart* part = map->getCurrentPart();
	AddObjectsUndoStep* add_step = new AddObjectsUndoStep(map);
	add_step->addObject(part->findObjectIndex(edited_path), edited_path);
	map->removeObjectFromSelection(edited_path, false);
	map->deleteObject(edited_path, true);
	map->setObjectsDirty();
	
	DeleteObjectsUndoStep* delete_step = new DeleteObjectsUndoStep(map);
	
	PathObject* holes = nullptr; // if the edited path contains holes, they are saved in this temporary object
	if (edited_path->parts().size() > 1)
	{
		holes = edited_path->duplicate()->asPath();
		holes->deletePart(0);
	}
	
	bool ok; Q_UNUSED(ok); // "ok" is only used in Q_ASSERT.
	PathObject* parts[2] = { new PathObject { edited_path->parts().front() }, nullptr };
	const PathPart& drag_part = edited_path->parts()[drag_part_index];
	if (drag_part.isClosed())
	{
		parts[1] = new PathObject { *parts[0] };
		
		parts[0]->changePathBounds(drag_part_index, drag_start_len, end_path_coord.clen);
		ok = parts[0]->connectIfClose(split_path, split_threshold);
		Q_ASSERT(ok);

		parts[1]->changePathBounds(drag_part_index, end_path_coord.clen, drag_start_len);
		ok = parts[1]->connectIfClose(split_path, split_threshold);
		Q_ASSERT(ok);
	}
	else
	{
		float min_cut_pos = qMin(drag_start_len, end_path_coord.clen);
		float max_cut_pos = qMax(drag_start_len, end_path_coord.clen);
		float path_len = drag_part.path_coords.back().clen;
		if (min_cut_pos <= 0 && max_cut_pos >= path_len)
		{
			ok = parts[0]->connectIfClose(split_path, split_threshold);
			Q_ASSERT(ok);
			
			parts[1] = new PathObject { *split_path };
			parts[1]->setSymbol(edited_path->getSymbol(), false);
		}
		else if (min_cut_pos <= 0 || max_cut_pos >= path_len)
		{
			float cut_pos = (min_cut_pos <= 0) ? max_cut_pos : min_cut_pos;
			parts[1] = new PathObject { *parts[0] };
			
			parts[0]->changePathBounds(drag_part_index, 0, cut_pos);
			ok = parts[0]->connectIfClose(split_path, split_threshold);
			Q_ASSERT(ok);
			
			parts[1]->changePathBounds(drag_part_index, cut_pos, path_len);
			ok = parts[1]->connectIfClose(split_path, split_threshold);
			Q_ASSERT(ok);
		}
		else
		{
			parts[1] = new PathObject { *parts[0] };
			PathObject* temp_path = new PathObject { *parts[0] };
			
			parts[0]->changePathBounds(drag_part_index, min_cut_pos, max_cut_pos);
			ok = parts[0]->connectIfClose(split_path, split_threshold);
			Q_ASSERT(ok);
			
			parts[1]->changePathBounds(drag_part_index, 0, min_cut_pos);
			ok = parts[1]->connectIfClose(split_path, split_threshold);
			Q_ASSERT(ok);
			
			temp_path->changePathBounds(drag_part_index, max_cut_pos, path_len);
			ok = parts[1]->connectIfClose(temp_path, split_threshold);
			Q_ASSERT(ok);
			
			delete temp_path;
		}
	}
	
	// If the object had holes, check into which parts they go
	if (holes)
	{
		for (const auto& hole : holes->parts())
		{
			PathPartVector::size_type part_index = (parts[0]->isPointOnPath(MapCoordF(holes->getCoordinate(hole.first_index)), 0, false, false) != Symbol::NoSymbol) ? 0 : 1;
			parts[part_index]->getCoordinate(parts[part_index]->getCoordinateCount() - 1).setHolePoint(true);
			parts[part_index]->appendPathPart(hole);
		}
	}
	
	for (auto& object : parts)
	{
		map->addObject(object);
		delete_step->addObject(part->findObjectIndex(object));
		map->addObjectToSelection(object, false);
	}
	
	CombinedUndoStep* undo_step = new CombinedUndoStep(map);
	undo_step->push(add_step);
	undo_step->push(delete_step);
	map->push(undo_step);
	map->setObjectsDirty();
	
	pathAborted();
}