系列目录:
【QGIS二次开发】地图显示与交互-01_qgis二次开发加载地图案例-优快云博客
【QGIS二次开发】地图显示与交互-02_setlayerlabeling-优快云博客
4.4 移动要素
首先在软件中添加任意数据,并选中数据开始编辑模式(示例中为点数据)。

图 41 移动要素
通过选择选取要素(可以直接按区域选择选取一片)。

图 42 框选需要移动的要素
左侧工具栏的移动选项。

图 43 移动按键
通过鼠标左键点击以及释放完成移动,将要素移动到自己想要的位置。

图 44 移动成功
实现核心代码如下,这段代码是基于QGIS插件的地图操作功能。在鼠标左键按下时,记录起始坐标,并找到选中要素上最近的点。在鼠标左键释放时,记录结束坐标,将选中要素上最近的点移动到该坐标,然后更新图层并刷新地图显示。整体实现了通过鼠标交互移动选中要素的功能。
void QgsMapToolMovePoint::canvasPressEvent(QgsMapMouseEvent* e)
{
if (e->button() == Qt::LeftButton) {
double xc = e->x();
double yc = e->y();
// 得到当前坐标变换对象
const QgsMapToPixel* pTransform = m_mapCanvas->getCoordinateTransform();
// 转换成地图坐标并记录为起始坐标
startpoint.setX(pTransform->toMapCoordinates(xc, yc).x());
startpoint.setY(pTransform->toMapCoordinates(xc, yc).y());
QgsFeatureIterator selectedFeatureIt = m_currentlayer->getSelectedFeatures();
QgsFeature selectedFeature;
while (selectedFeatureIt.nextFeature(selectedFeature)) { // 只循环一次
QgsGeometry geom = selectedFeature.geometry();
double sqrDist; // 最近距离
QgsPointXY nearestPoint = geom.closestVertex(startpoint, closestVertexIndex, previousVertexIndex, nextVertexIndex, sqrDist);
}
}
}
void QgsMapToolMovePoint::canvasReleaseEvent(QgsMapMouseEvent* e)
{
if (e->button() == Qt::LeftButton) {
double xc = e->x();
double yc = e->y();
// 得到当前坐标变换对象
const QgsMapToPixel* pTransform = m_mapCanvas->getCoordinateTransform();
// 转换成地图坐标
endpoint.setX(pTransform->toMapCoordinates(xc, yc).x());
endpoint.setY(pTransform->toMapCoordinates(xc, yc).y());
// 线上加点
QgsFeatureIterator selectedFeatureIt = m_currentlayer->getSelectedFeatures();
QgsFeature selectedFeature;
while (selectedFeatureIt.nextFeature(selectedFeature)) { // 只循环一次
QgsGeometry geom = selectedFeature.geometry();
geom.moveVertex(endpoint.x(), endpoint.y(), closestVertexIndex);
// 更新要素的几何体
m_currentlayer->startEditing();
selectedFeature.setGeometry(geom);
m_currentlayer->updateFeature(selectedFeature);
//m_currentlayer->commitChanges();
}
m_mapCanvas->refresh();
m_mapCanvas->refreshAllLayers();
}
}
4.5 删除要素
首先在软件中添加任意数据,并选中数据开始编辑模式(示例中为面数据)。

图 45 示例数据
通过选择选取要素(可以直接按区域选择选取一片),并可以通过打开属性表确定删除前共计113个要素。

图 46 选择要素
选择删除操作。

图 47 删除操作
操作完成,要素在图层中消失,且可以打开属性表开出现在共111个要素。

图 48 删除成功
核心代码如下,这段代码是QGIS插件中的一个地图编辑工具类,实现了删除选中要素的功能。在deleteFeature函数中,遍历选中图层的选中要素,通过编辑缓冲区删除这些要素的记录。最后,刷新地图显示,实现删除操作的更新效果。
QgsMapToolEditFeature::~QgsMapToolEditFeature() {};
void QgsMapToolEditFeature::deleteFeature() {
QgsFeatureIterator selectedFeatureIt = m_currentlayer->getSelectedFeatures();
QgsFeature selectedFeature;
m_currentlayer->startEditing();
QgsVectorLayerEditBuffer* editBuffer = m_currentlayer->editBuffer();
if (!editBuffer) {
return;
}
while (selectedFeatureIt.nextFeature(selectedFeature)) {
editBuffer->deleteFeature(selectedFeature.id());
}
//m_currentlayer->commitChanges();
m_currentlayer->triggerRepaint();
m_mapCanvas->refresh();
m_mapCanvas->refreshAllLayers();
}
4.6 复制要素
首先在软件中添加任意数据,并选中数据开始编辑模式(示例中为线数据)。

图 49 示例数据
通过选择选取要素(可以直接按区域选择选取一片),并可以打开属性表看出现在共4个要素。

图 50 选择要素
选择复制操作。

图 51 复制按键
操作完成,复制出的新要素出现在图层正中(为了便于展示复制操作成功完成的特意设定),且可以打开属性表开出现在共6个要素。

图 52 复制成功
核心代码如下,这段代码是QGIS插件中的地图编辑工具类,实现了复制选中要素的功能。在copyFeature函数中,首先获取选中图层的选中要素,并计算选中要素中心点与当前地图中心点的偏移。然后遍历选中要素,复制其几何体并根据偏移添加到编辑缓冲区中,最后刷新地图显示,实现复制操作的更新效果。
void QgsMapToolEditFeature::copyFeature() {
QgsFeatureIterator selectedFeatureIt = m_currentlayer->getSelectedFeatures();
QgsFeature selectedFeature;
m_currentlayer->startEditing();
QgsVectorLayerEditBuffer* editBuffer = m_currentlayer->editBuffer();
if (!editBuffer) {
return;
}
QgsRectangle currentExtent = m_currentlayer->extent();
QgsFeature firstFeature; // 记录第一个要素
if (selectedFeatureIt.nextFeature(firstFeature)) {
// 记录第一个要素的中心点和当前地图的中心点
QgsPointXY centerPointFirst = firstFeature.geometry().centroid().asPoint();
QgsPointXY centerPointMap = currentExtent.center();
// 计算移动方向和距离
double xOffset = centerPointMap.x() - centerPointFirst.x();
double yOffset = centerPointMap.y() - centerPointFirst.y();
selectedFeatureIt = m_currentlayer->getSelectedFeatures(); // 重新获取选中的要素
while (selectedFeatureIt.nextFeature(firstFeature)) {
QgsFeature newFeature(firstFeature);
QgsFeatureId id = firstFeature.id();
newFeature.setId(QgsFeatureId());
QgsGeometry geometry = newFeature.geometry();
geometry.translate(xOffset, yOffset);
editBuffer->changeGeometry(id, geometry);
editBuffer->addFeature(newFeature);
}
}
//m_currentlayer->commitChanges();
m_currentlayer->triggerRepaint();
m_mapCanvas->refresh();
m_mapCanvas->refreshAllLayers();
}
4.7 旋转要素
首先在软件中添加任意数据,并选中数据开始编辑模式(示例中为线数据)。

图 53 示例数据
通过选择选取要素(可以直接按区域选择选取一片)。

图 54 选择要素
选择旋转操作。

图 55 旋转操作
按下鼠标左键后通过鼠标的拖动实现完成要素的实时旋转效果(蓝色虚线框也是特设的效果)显示,松开鼠标后停止旋转。

图 56 旋转成功
核心代码如下,这段代码是一个QGIS插件的地图编辑工具,实现了通过鼠标拖动旋转选中要素的功能。鼠标左键按下时记录起始点和选中要素的几何图形,鼠标移动时计算旋转角度并更新要素的几何图形,鼠标释放时结束旋转。
void QgsMapToolTurn::canvasPressEvent(QgsMapMouseEvent* e) {
// 检查是否是鼠标左键点击事件
if (e->button() == Qt::LeftButton) {
m_startPoint = e->mapPoint().toQPointF();
m_dragging = true;
// 获取选中要素的几何图形
QgsFeatureIterator selectedFeatureIt = m_currentLayer->getSelectedFeatures();
QList<QgsGeometry> geometries;
QgsFeature selectedFeature;
while (selectedFeatureIt.nextFeature(selectedFeature)) {
geometries << selectedFeature.geometry();
}
// 计算旋转的中心
QgsRectangle boundingBox = geometries.at(0).boundingBox();
for (const QgsGeometry& geometry : geometries) {
boundingBox.combineExtentWith(geometry.boundingBox());
}
m_initialBoundingBox = boundingBox; // 保存初始的外接矩形
m_BoundingBox = QgsGeometry::fromRect(m_initialBoundingBox);
// 绘制外包矩形
pRubBand->addGeometry(m_BoundingBox);
}
// 检查是否是鼠标右键点击事件
else if (e->button() == Qt::RightButton) {
m_dragging = false;
}
}
void QgsMapToolTurn::canvasReleaseEvent(QgsMapMouseEvent* e) {
if (m_dragging && e->button() == Qt::LeftButton) {
pRubBand->reset(QgsWkbTypes::NullGeometry);
m_dragging = false; // 结束拖动
}
}
void QgsMapToolTurn::canvasMoveEvent(QgsMapMouseEvent* e) {
if (!m_currentLayer->isEditable()) {
m_currentLayer->startEditing();
}
if (m_dragging && e->buttons() & Qt::LeftButton) {
// 获取当前拖动的位置
QPointF currentPoint = e->mapPoint().toQPointF();
// 计算拖动的偏移量
QPointF offset = currentPoint - m_startPoint;
// 获取选中要素的几何图形
QgsFeatureIterator selectedFeatureIt = m_currentLayer->getSelectedFeatures();
QList<QgsGeometry> geometries;
QgsFeature selectedFeature;
while (selectedFeatureIt.nextFeature(selectedFeature)) {
geometries << selectedFeature.geometry();
}
QgsPointXY center = m_initialBoundingBox.center();
// 计算角度(以弧度为单位)
double offsetAngle = qAtan2(offset.y(), offset.x());
double rotationDelta = offsetAngle - qAtan2(center.y() - m_startPoint.y(), center.x() - m_startPoint.x());
// 绘制虚线框
pRubBand->reset(QgsWkbTypes::LineGeometry);
m_BoundingBox.rotate(rotationDelta, center);
pRubBand->addGeometry(m_BoundingBox);
// 旋转选中的要素
selectedFeatureIt = m_currentLayer->getSelectedFeatures();
while (selectedFeatureIt.nextFeature(selectedFeature)) {
QgsGeometry geometry = selectedFeature.geometry();
// 旋转
geometry.rotate(rotationDelta, center);
// 更新几何图形
m_currentLayer->changeGeometry(selectedFeature.id(), geometry);
}
m_mapCanvas->refresh();
m_startPoint = currentPoint; // 更新起始点
}
}

2924

被折叠的 条评论
为什么被折叠?



