2

Using the field calculator one can update the geometry of a feature in dependence of one of its attributes. The process is described in Updating feature geometry from attribute fields in QGIS

My goal is to update rectangles depending on "width" and "height" attributes. I have the formula to do so. The formula works and I have saved it as a custom expression. And updating the geometry using the field calculator works like a charm as well. However it is quite tedious to

  1. Change the attribute.
  2. Open field calculator
  3. Select field
  4. Select the custom formula to update geometry depending on width or height
  5. Select update field

It is possible to link attribute fields (e.g. length of a line, area of a polygon etc.) to the geometry, such that they automatically update when the geometry is edited - see Automatically updating geometry attributes in QGIS without using Virtual Fields

Is there a way to switch this arround, so that the geometry automatically adapts, when i edit the width and height attributes without me having to manually perform the 5 steps above?

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
asked Sep 8, 2022 at 20:30
2
  • Using a virtual layer...? Commented Sep 8, 2022 at 21:15
  • Hmm could work, however i would prefer not to clutter up my project with yet another Layer. Currently looking to write a custom action using pyqgis, so the workflow to update geometry would be reduced to 1 step instead of 5. However the preferred solution remains an automatic geometry update... Commented Sep 9, 2022 at 14:16

1 Answer 1

2

I ended up writing a custom python Script to achieve what i was looking for:

from qgis.core import *
import math 
layer = qgis.utils.iface.activeLayer()
def addHeight(fromPoint, newHeight, angle):
 newX = fromPoint.x() - math.sin(math.radians(angle)) * newHeight 
 newY = fromPoint.y() + math.cos(math.radians(angle)) * newHeight 
 return QgsPointXY(newX,newY)
def addWidth(fromPoint, newWidth, angle):
 newX = fromPoint.x() + math.cos(math.radians(angle)) * newWidth 
 newY = fromPoint.y() + math.sin(math.radians(angle)) * newWidth 
 return QgsPointXY(newX,newY)
def createNewRectangle(oldGeom, newHeight, newWidth, angle): 
 lowerLeft = oldGeom[0][0]
 lowerRight = addWidth(lowerLeft, newWidth, angle)
 uperRight = addHeight(lowerRight, newHeight, angle)
 upperLeft = addHeight(lowerLeft, newHeight, angle)
 newGeom = [] 
 newGeom.append(lowerLeft) 
 newGeom.append(lowerRight) 
 newGeom.append(uperRight) 
 newGeom.append(upperLeft) 
 return [newGeom]
def update(fid, idx, value):
 attribute = layer.attributeDisplayName(idx)
 print(f"fid = {fid}, attribute = {attribute}, value = {value}")
 feature = layer.getFeature(fid)
 ansicht_hoehe_neu = \
 (float(feature["seite_hoehe"]) \
 - feature["seitenrand_oben"] \
 - feature["seitenrand_unten"]) \
 * feature["massstab"] / 1000.0
 ansicht_breite_neu = \
 (float(feature["seite_breite"]) \
 - feature["seitenrand_links"] \
 - feature["seitenrand_rechts"] \
 - feature["breite_schriftfeld"]) \
 * feature["massstab"] / 1000.0
 winkel = feature["winkel"]
 oldRectangle = feature.geometry().asPolygon()
 newRectangle = createNewRectangle(oldRectangle, ansicht_hoehe_neu, ansicht_breite_neu, winkel) 
 
 if newRectangle != oldRectangle:
 newGeom = QgsGeometry.fromPolygonXY(newRectangle)
 layer.changeGeometry(fid, newGeom)
 
layer.attributeValueChanged.connect(update)

This script only works for rectangles. It basically connects attribute changes of the active layer (meaning the layer which is selected layer at the time the script is started) and connects attribute changes of that layer to the update-function.

It is assumed, that the layer has the following attributes (attribute names are in german - english translation is given in brackets)

  • seite_hoehe (page height)
  • seite_breite (page width)
  • seitenrand_links (page margin left)
  • seitenrand_rechts (page margin right)
  • seitenrand_oben (page margin top)
  • seitenrand_unten (page margin bottom)
  • massstab (scale)
  • winkel (angle)

The attributes are used to calculate the resulting width and height of the world view and then (using the angle) to create a new rectangle to represent said world view and assign that rectangle as geometry of the corresponding object.

All in all this is a very "plan-centric" approach. The attributes representing angle, page width etc. have the advantage, that they can be "reused" to control the page layout of every single plan using a layout with atlas-functionality and heavy us of data driven overrides.

So basically in the end multiple plans with varying scales, rotations, page width and heights can be created using a single vector layer and a corresponding layout with atlas functionality.

Vince
20.5k16 gold badges49 silver badges65 bronze badges
answered Apr 15, 2024 at 11:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.