Overview & Philosophy
PlanX CAD Toolset is a drafting-grade CAD workbench for QGIS that brings the muscle-memory workflow of AutoCAD to the geospatial canvas. It is not a map-digitizing aid bolted onto QGIS — it is a complete two-dimensional drafting environment: a command line with AutoCAD-style aliases, precision point entry in metres, native snapping, transactional geometry editing, managed output layers, and a family of urban road-design tools written specifically for the planning classroom and the drafting desk.
The plugin is built on a small set of engineering commitments that govern every tool. Keyboard-first: every tool has a command alias, fits the command-line loop (alias → tool key → fuzzy name match), and honours empty-Enter repeat. Metre-accurate everywhere: every distance-bearing operation — offset, fillet, chamfer, buffer, hatch, road generation, precision input — resolves in a local metric work CRS so that a 5 m offset is a true 5 m on the ground even when the project uses a geographic CRS. Topology-safe: geometry edits run inside QGIS edit commands with rollback, two-step tools refuse to operate on themselves, and multipart, curve, and Z/M geometry survives every transform. Global English: one consistent English interface and documentation set for international teams.
Design principle. PlanX CAD Toolset adds CAD-level primitives. Heavier, domain-complete workflows stay with their dedicated siblings in the PlanX ecosystem — parcel subdivision in ParcelFlux, publication cartography in CartoLab, master-plan automation in the UIP and Settlement toolsets. The CAD toolset integrates with rather than duplicates those workflows.
Quick Start
First-time setup. Open the PlanX CAD dock from the toolbar icon (or Plugins → PlanX CAD Toolset). The dock shows the command line, collapsible tool groups, recent tools, and a live layer-state indicator. There are no dependencies to install and no configuration step — the plugin uses only the QGIS API that ships with QGIS 3.28 LTR through QGIS 4.
The fastest path to a first drawing: ensure a vector layer is active and editable, then type L and press Enter to start Line — two clicks and the tool auto-finishes. Type F for Fillet, TR for Trim, CO for Copy. An empty Enter repeats the last command; ↑/↓ recall history. For exact placement, type a number, -, or @ directly on the canvas to enter precision input: @10,0 is 10 m east of the last vertex, @25<45 is 25 m at 45°, and a bare 12.5 is 12.5 m along the cursor bearing.
Recommended order for a first project: draw with the Draw group (01), add references with Construction lines (02), refine geometry with the Modify tools (03), position it with the Transform group (04), verify with Measure & Annotate (05), and generate road platforms with the Urban Planning tools (06).
Drafting Workflow
00
Command Line
alias → tool → fuzzy
→
→
→
→
→
→
06
Urban Planning
3 tools
Linear flow recommended for a first drawing; experienced users may enter at any group. The Systems sections describe the shared machinery — command line, precision input, managed layers, CRS safety, and edit-session safety — that every tool relies on.
Six primitive drafting tools. All six write to the active editable vector layer, honour native QGIS snapping, accept precision point input, and share one key model — Esc cancels, Backspace/Z undoes the last vertex, Enter finishes. Line, Polyline and Arc require a line layer; Rectangle, Polygon and Circle require a polygon layer.
Draws a single straight segment between two points. It is the workhorse primitive: every sketch, centreline, and boundary starts here, and because it auto-finishes after the second click it is the fastest way to lay down a single edge.
1. How It Works
The tool subclasses SketcherBase. Each canvas press is first routed through QGIS's native QgsSnappingUtils.snapToMap(), so the point is snapped before it is stored. Once two vertices are recorded the tool auto-finishes, building the geometry with QgsGeometry.fromPolylineXY(vertices) and writing it to the active line layer through add_geometry_to_current_layer(), which auto-starts editing, transforms canvas CRS to layer CRS when they differ, and rejects a geometry-type mismatch.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Places vertex 1 (start). |
| 2 | Left-click | Places vertex 2 and finishes — the segment is committed. |
| — | Backspace / Z | Undo the last vertex (before finishing). |
| — | Esc | Cancel the in-progress sketch. |
3. Output & Behaviour
A LineString feature is added to the active editable line layer. Attributes take the layer's default values. The tool stays active after committing, so consecutive lines can be drawn without re-issuing the command.
4. Usage & Tips
Precision. Type @dx,dy for a metre-exact second vertex relative to the first, or a bare distance to place it a fixed number of metres along the cursor bearing. Topology. Keep snapping enabled and let the snap marker confirm the endpoint lands on an existing vertex or edge — this is what makes later Fillet/Trim/Join operations clean. Continuous drawing. Use Polyline rather than repeated Lines when the segments form one continuous feature.
Draws a connected sequence of line segments as a single continuous feature. It is the correct tool for long chains, road centrelines, and parcel boundaries that must remain one geometry rather than many separate Lines.
1. How It Works
Each left-click appends a snapped vertex; the vertex count is unbounded. Right-click or Enter finishes once at least two vertices exist; Backspace/Z pops the last vertex and rebuilds the rubber-band preview; Esc cancels. On finish the tool builds QgsGeometry.fromPolylineXY(vertices) and commits to the active line layer.
2. Interaction
| Step | Input | Result |
| 1..n | Left-click | Append a vertex to the chain. |
| finish | Right-click / Enter | Commit the polyline (requires ≥ 2 vertices). |
| undo | Backspace / Z | Remove the last vertex. |
| cancel | Esc | Discard the sketch. |
3. Output & Behaviour
A single LineString feature with an arbitrary number of vertices is added to the active line layer. Unlike a series of Lines, the whole chain is one feature — one attribute row, one selectable object, one geometry for downstream editing.
4. Usage & Tips
When to prefer Polyline. Any continuous edge with more than two vertices. Splitting later is easy with
Break or
Divide; welding separate Lines back together requires
Join, so start continuous when the feature is logically continuous.
Undo granularity. Backspace removes one vertex at a time, giving cheap correction during sketching.
Draws an axis-aligned rectangle from two opposite corners. It is the go-to primitive for building footprints, plot boundaries, and layout blocks, and it is explicitly geographic-CRS-safe: the right angles are computed in a local metric CRS so a "rectangle" is truly rectangular on the ground.
1. How It Works
Two opposite-corner clicks are recorded. The four corners are formed by swapping the x and y of the two picked points:
corners = [ first, (opposite.x, first.y), opposite, (first.x, opposite.y), first ]
The ring is closed by repeating the first point. In a projected CRS the corner swap happens directly in canvas units; in a geographic CRS both corners are first transformed to local_metric_crs(first, canvas_crs), the axis-aligned corner swap is performed there, and all five points are transformed back — so the sides are right-angle and parallel in metres, not in degrees. The result is a closed-ring polygon.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | First opposite corner. |
| 2 | Left-click | Second opposite corner — rectangle committed. |
3. Output & Behaviour
A Polygon feature (closed ring) is added to the active polygon layer. The tool auto-finishes after the second click and stays active for the next rectangle.
4. Usage & Tips
Geographic projects. Because the corners are resolved in a local metric CRS, a rectangle drawn on an EPSG:4326 layer has genuinely right angles on the ellipsoid — important when the feature later drives offset, hatch, or road generation. Precision. Combine with @dx,dy to define the second corner exactly relative to the first.
Draws a regular polygon (an equilateral N-gon) from a centre point and an edge point that sets radius and orientation. It is the tool for plan-form primitives — plazas, roundabouts, park parcels — where a perfectly regular shape is required.
1. How It Works
On activation a side-count dialog is shown. The first canvas click places the centre; the second places an edge point. The vertex set is computed as:
radius = |edge − centre|; start_angle = atan2(edge.y − centre.y, edge.x − centre.x)
anglei = start_angle + 2π · i / sides, for i = 0 … sides
Vertices are evenly spaced at 2π/sides increments; the first vertex sits on the bearing from the centre to the second click (so the user controls orientation by where they place the edge point), and the ring is closed by emitting sides + 1 points. Geographic CRS → local-metric round-trip as with Rectangle. The result is a closed-ring polygon.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Number of sides | Integer | 6 | 3 – 100 | Side count of the regular polygon (6 = hexagon). |
3. Interaction
| Step | Input | Result |
| 0 | Dialog | Enter the number of sides (cancel aborts the tool). |
| 1 | Left-click | Places the polygon centre. |
| 2 | Left-click | Sets radius + orientation and commits. |
4. Output & Behaviour
A regular Polygon is added to the active polygon layer. Orientation is under direct user control via the second click's bearing.
5. Usage & Tips
Orientation control. The first vertex lands on the centre→edge bearing, so to point a corner (not an edge) at north, place the edge point on the desired bearing.
Large N. A high side count approximates a circle but stays a polygon — use
Circle for a true curved boundary.
Draws a circle from a centre point and a radius point. Internally a circle is a 64-segment polygon (a curved boundary discretised for storage), generated by the same buffer primitive used by the Buffer tool.
1. How It Works
The first click is the centre, the second the radius point. In a projected CRS the radius is the Euclidean distance between the two points and the circle is produced with QgsGeometry.fromPointXY(center).buffer(radius, SEGMENTS) where SEGMENTS = 64. In a geographic CRS the centre and radius point are transformed to the local metric CRS, the radius recomputed with math.hypot(dx, dy), the buffer produced there, and the result transformed back — so the circle's radius is a true metre distance on the ground.
SEGMENTS = 64 (class constant); geometry = centre.buffer(radius, 64)
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Places the centre. |
| 2 | Left-click | Sets the radius and commits. |
3. Output & Behaviour
A Polygon (64 segments) is added to the active polygon layer. The 64-segment discretisation is fixed, not adaptive, so very large circles are piecewise-linear to that resolution.
4. Usage & Tips
Discretisation. 64 segments is a deliberate balance between smoothness and feature size; a circle that looks faceted at a large zoom is still topologically a single ring. Radius by precision input. Type a bare distance after placing the centre to set an exact metre radius along the cursor bearing.
Draws a circular arc through three points — start, an intermediate point, and end. The intermediate point determines both the curvature and, importantly, which of the two possible arcs through the endpoints is taken.
1. How It Works
Three clicks are recorded. The tool solves the circumcircle of the three points using the standard determinant formula:
D = 2·( ax(by−cy) + bx(cy−ay) + cx(ay−by) )
centrex = [ (ax²+ay²)(by−cy) + (bx²+by²)(cy−ay) + (cx²+cy²)(ay−by) ] / D
centrey = [ (ax²+ay²)(cx−bx) + (bx²+by²)(ax−cx) + (cx²+cy²)(bx−ax) ] / D
If |D| < 10⁻¹⁰ the points are collinear and the tool returns a straight polyline instead. Otherwise the radial angles a1, a2, a3 are computed with atan2 and normalised to [0, 2π). The sweep direction is decided by whether d12 < d13 (where d12 = (a2−a1) mod 2π, d13 = (a3−a1) mod 2π): the arc travels from a1 to a3 through the intermediate angle a2. The arc is then discretised into ARC_SEGMENTS = 32 equal steps (33 emitted points) and stored as a LineString.
2. Geometric Formulation
This is the three-point-circumcircle construction (see O'Rourke 1998 and the Graphics Gems collections). Note two deliberate behaviours. First, the arc is not forced to be the shorter of the two possible arcs: it is the arc that passes through the intermediate point, so a three-point arc spanning more than 180° produces a major arc. Second, the segment count is fixed at 32 — the arc is a polyline approximation of a true circle, not a QGIS curve geometry, so it can live on a plain line layer.
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Arc start point. |
| 2 | Left-click | Intermediate point (sets curvature + arc side). |
| 3 | Left-click | Arc end point — committed. |
4. Output & Behaviour
A 32-segment LineString arc is added to the active line layer. Collinear input degenerates to a straight three-point polyline rather than failing.
5. Usage & Tips
Arc side. The intermediate point is not merely a "bulge" hint — it selects which of the two arcs through start and end is drawn. Move the intermediate point to the opposite side of the chord to flip the arc. Major arcs. To draw a large sweeping arc (greater than a semicircle), place the intermediate point so the sweep passes through it on the long way around.
6. Literature
O'Rourke, J. (1998). Computational Geometry in C (2nd ed.) — the circumcircle and collinearity test used here. Goldman, R. (2003). Pyramid Algorithms — parametric circle/arc evaluation. Glassner, A. S. (Ed.) (1990). Graphics Gems — robust three-point circle fitting. Full citations in the references appendix.
Non-printing reference geometry — infinite axes, one-directional rays, and bounded segments — for alignment and layout. Construction lines write to their own dashed-cyan managed layer rather than the working layer, so they never pollute the deliverable.
Creates reference lines in three modes — Infinite (extends through both points, re-extended on repaint), Ray (extends forward from the first point only), and Segment (bounded by the two clicks). These are the CAD equivalent of the drafting construction line: always there for alignment, never part of the printed plan.
1. Modes
| Mode | Alias | Shortcut | Behaviour |
| Infinite | XL / XLINE | Ctrl+Shift+K | Extends through both points in both directions by 10× the canvas diagonal. |
| Ray | RAY | Ctrl+Alt+K | Extends forward from the first click through the second, by 10× the canvas diagonal. |
| Segment | SEG | Ctrl+Alt+L | Bounded line from the first to the second click. |
2. How It Works
Two clicks define the direction. The infinite and ray modes extend by _INF_EXTEND_FACTOR = 10.0 times the canvas diagonal so the reference line always spans the visible canvas (and re-extends on pan/zoom). A degenerate two-click pair (norm ≤ 1e-9) is returned as-is rather than failing. Each line is written as a LineString to the managed planx_construction layer and styled with a dashed cyan pen (0,188,212, width 0.4, round cap) applied once via a custom-property guard.
3. Interaction
| Step | Input | Result |
| 1 | Left-click | First reference point. |
| 2 | Left-click | Second reference point — line committed, tool continues. |
| — | Right-click | Reset to the first point. |
| — | Esc | Cancel the tool. |
4. Output & Behaviour
Features land on the managed planx_construction layer (LineString) with fields:
| Field | Type | Description |
| mode | string | infinite / ray / segment |
| from_x, from_y | double | First reference point coordinates. |
| to_x, to_y | double | Second reference point coordinates. |
5. Usage & Tips
Alignment axes. Draw two perpendicular infinite lines as a site grid, then snap drawing features to their intersections. Separation. Because construction geometry lives on its own layer, it can be hidden or deleted in one action without touching working geometry. Ray vs infinite. Use a ray when the reference has a meaningful origin and a single direction of interest.
Sixteen editing tools that reshape existing geometry. The two-step tools (Trim, Extend, Fillet, Chamfer, Break) use a shared pick aperture with self-pick exclusion, so the second pick never re-selects the first feature. Most write back to the picked layer; output tools (Buffer, Hatch) write to their own managed layers.
Creates a parallel copy of a selected feature at a specified metre distance on the clicked side. It is the fundamental "copy this edge a fixed distance away" operation that underlies setback drafting and road-platform generation.
1. How It Works
After the distance is entered and the feature picked, the tool transforms the feature into a local metric CRS (from the feature centroid) so the distance is true metres. It computes QgsGeometry.offsetCurve(distance, 8, Qgis.JoinStyle.Round, 2.0) on both sides, then selects the side whose result is nearer the click point (left.distance(click) vs right.distance(click)). The chosen curve is transformed back to the layer CRS and added as a new feature with attributes copied from the source.
offsetCurve(d, segments=8, join=Round, miterLimit=2.0) — computed on both sides, click selects the side
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Offset distance | Double | 5.0 m | 0.01 – 100 000 | Perpendicular distance of the parallel copy. |
3. Interaction
| Step | Input | Result |
| 1 | Dialog | Enter offset distance (m). |
| 2 | Left-click | Pick the feature to offset. |
| 3 | Left-click | Click the side to offset toward. |
4. Output & Behaviour
A new parallel feature is added to the picked layer, with all attributes copied from the source. A valid source CRS is required; if only one side is computable it is used, and if neither is, the tool reports Offset could not be calculated.
5. Usage & Tips
Setback drafting. Offset a parcel boundary inward by the setback distance to obtain the buildable envelope.
Side selection. The side is resolved by proximity to the click, so click clearly to one side of the feature.
Many offsets at once. Use
Multi-Offset for several distances in one pass.
6. Literature
The parallel-curve (offset) construction and its straight-skeleton relationship follow from de Berg et al. (2008); the round-join offsetCurve is QGIS's GEOS implementation of that construction. See the references appendix.
Offsets a selected line several times at once from a comma-separated list of distances, on one side, both sides, or a side chosen on the canvas. It collapses what would otherwise be a long sequence of Offset commands into a single operation.
1. Parameters
| Parameter | Type | Default | Options | Description |
| Distances (m) | Text | "3.0, 6.0" | comma-separated | List of offset distances; each is abs(float(v)), invalid entries ignored. |
| Direction | Enum | Both | Left / Right / Both / Pick Side on Canvas | Which side(s) to offset toward. |
2. How It Works
Distances are parsed by splitting on commas. For each distance the tool calls the shared offset_geometry helper — offsetCurve(d, 8, Qgis.JoinStyle.Round, 2.0) — on the requested side(s), transforms results back to the layer CRS, and batch-adds them as new features with copied attributes. In Pick Side on Canvas mode the first distance is tested on both sides and the nearer is chosen.
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the line to offset. |
| 2 | Dialog | Enter distances + direction; Apply. |
| 3 | (Left-click) | Only when direction = Pick Side on Canvas — choose the side. |
4. Output & Behaviour
Parallel lines are added to the source layer (attributes copied). Line geometry only; an empty geometry or a list with no valid distance is reported as an error rather than silently producing nothing.
5. Usage & Tips
Road-edge fan-out. A single centreline offset at
3, 6, 9, 12 on both sides yields the lane edges of a symmetric cross-section in one step — the same geometry the
Road Platform Generator formalises with attributes.
Both. The default produces mirror pairs, which is the common case for axis-based drafting.
Trims a target line against a cutting boundary, removing the side nearest the click. It is the classic two-step CAD trim: pick the knife, then pick the part to remove.
1. How It Works
The first click selects the cutting boundary; the second click re-picks a target feature excluding the boundary (self-pick protection). The boundary is transformed into the target's CRS, and intersection points are computed, ordered along the target with lineLocatePoint, and used to split it with splitGeometry(points, False). The segment nearest the click is removed and the rest kept. If the split yields fewer than two segments, a fallback subtracts a narrow buffer (cutting.buffer(0.001, 4)) and keeps the part farthest from the click.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the cutting boundary. |
| 2 | Left-click | Pick the target line near the side to remove. |
3. Output & Behaviour
The target feature's geometry is replaced with the kept portion. On a single-part layer, if a second surviving part results it is added as a new feature with copied attributes (edit command PlanX CAD: trim). A feature cannot trim itself; a non-intersecting boundary produces no change.
4. Usage & Tips
Click side matters. The segment nearest your click is the one removed — click clearly on the overhang to delete.
Self-pick. Because the boundary is excluded from the second pick, a line can be trimmed against a nearby line without accidentally re-selecting the boundary.
Pair with Extend. Trim removes overhang;
Extend adds reach — the two together resolve most endpoint conditions.
Extends a line until it meets a selected boundary, projecting forward along the direction of its final segment. It is the complement to Trim — adding reach to an undershooting line instead of removing overhang.
1. How It Works
After the boundary is picked, the target's final segment direction is read and a ray is projected whose length is max(distance(endpoint, bbox_corner)) * 1.01 + segment_length over the four boundary bounding-box corners (an overshoot factor of 1.01 guarantees the ray clears the boundary). The ray is intersected with the boundary, only candidate vertices in front of the endpoint are kept (along > max(length·1e-9, 1e-12)), and the nearest one is appended to the line, preserving every existing vertex.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the boundary feature. |
| 2 | Left-click | Pick the line to extend (near the end to extend). |
3. Output & Behaviour
The target feature's geometry is updated with the extension appended. The boundary is excluded from the second pick (no self-extend). If no forward intersection exists, the tool reports Extension failed.
4. Usage & Tips
Endpoint conditions. Extend a road centreline to a site boundary before offsetting, so the offset edges run to the full extent. Direction. Extension follows the terminal segment's direction — extend a curved polyline and only the last segment's bearing is projected.
Rounds the corner between two intersecting lines with a tangent arc of a given radius, trimming both lines back to their tangent points. It solves the classic tangent-circle fillet problem and commits the two trims plus the arc as one undo step.
1. How It Works
The radius is entered first, then the two lines are picked. The tool solves in a local metric CRS: find the intersection point, the unit vectors toward the retained end of each line, and the included angle. Tangent distance and arc centre are computed from the radius, the arc is built through the shortest angular sweep with segments = 20, and each line is trimmed to its tangent point via trim_line_to_point. Both trims and the arc are written in a single PlanX CAD: fillet edit command.
2. Geometric Formulation
Let r be the fillet radius and θ the included angle between the two lines at their intersection. The tangent distance from the intersection to each tangent point, and the distance to the arc centre along the angle bisector, are:
dt = r / tan(θ/2), dc = r / sin(θ/2)
Tangent points are tpi = pinter + dt·vi; the centre is c = pinter + dc·(v₁+v₂)/|v₁+v₂|. The 20-segment arc runs through the shortest angular sweep and its first/last points are snapped exactly to the tangent points for topology safety. Parallel or collinear lines yield no result, and a line cannot fillet against itself.
3. Parameters
| Parameter | Type | Default | Constraints | Description |
| Fillet radius | Double | 2.0 m | 0.01 – 10 000 | Radius of the tangent arc. |
4. Output & Behaviour
Both source lines are trimmed to their tangent points, and a new arc feature is added to the first line's layer (attributes copied from the first feature). The whole operation is atomic — one edit command, full rollback on failure.
5. Usage & Tips
Radius vs leg length. The radius must fit within both retained legs; an oversized radius relative to a short line trims that line away.
Corner rounding. For a straight (non-arc) corner cut, use
Chamfer.
Block corners. For urban block-corner rounding across many corners, use
Block Chamfer.
6. Literature
The tangent-circle fillet is the canonical computational-geometry construction — see de Berg et al. (2008) and O'Rourke (1998). The bisector solution (r/tan(θ/2), r/sin(θ/2)) is the standard treatment in Farin (2002). Full citations in the references appendix.
Cuts a straight corner between two intersecting lines using two cutback distances, trimming both lines and adding a connecting segment. It is AutoCAD's distance-distance Chamfer: enter both cutbacks, pick the two lines, and the corner is resolved with a straight edge instead of an arc.
1. How It Works
Two cutback distances are collected (optionally equal). The intersection point and retained-end unit vectors are computed, cutback points are placed at dist1 and dist2 along each line, and a straight line connects them. Both source lines are trimmed to their cutback points and the chamfer line is added to the first layer in a single PlanX CAD: chamfer edit command. A cutback longer than the retained leg is rejected, as are parallel/collinear lines.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| First distance | Double | 5.0 m | 0.01 – 100 000 | Cutback along the first line. |
| Second distance | Double | 5.0 m | 0.01 – 100 000 | Cutback along the second line. |
| Use first for both | Checkbox | auto | enabled when equal | Mirror the first distance to the second (symmetric cut). |
3. Interaction
| Step | Input | Result |
| 1 | Dialog | Enter both cutback distances (or tick "use first for both"). |
| 2 | Left-click | Pick the first line. |
| 3 | Left-click | Pick the second line — chamfer committed. |
4. Output & Behaviour
Both lines are trimmed to their cutback points and a new chamfer line feature is added to the first layer (attributes copied). Distances stay metre-accurate in geographic projects via the local metric CRS.
5. Usage & Tips
Equal vs unequal. Equal cutbacks give a symmetric corner; unequal cutbacks give a skewed cut, useful for matching two road edges of different character.
Rejection. A cutback longer than the retained leg is refused rather than corrupting the source line.
Urban block corner. The general Chamfer is a two-line command; for one-click urban block-corner resolution across all project lines, use
Block Chamfer.
Splits a line into two parts, either at a single point (no gap) or by removing the span between two points (with a gap). It is AutoCAD's Break — the clean way to sever a line or open a gap in it.
1. How It Works
Both break points are located along the line with lineLocatePoint, with a numeric tolerance of max(total·1e-9, 1e-12). One point splits into [0, first] and [first, total]; two points keep [0, low] and [high, total] (removing the span between). Segmentation uses line_substring, which walks cumulative segment distances and therefore preserves every interior vertex of the original. The first part replaces the feature; the second is added as a new feature with copied attributes.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the line to break. |
| 2 | Left-click | First break point. |
| 3 | Left-click / Enter | Second point (removes the span) — or Enter/right-click to break at one point only. |
3. Output & Behaviour
The picked feature keeps the first part; the remainder is added as a new feature with the same attributes. A break point must lie strictly between the line's endpoints; a break on an endpoint is refused. A gap reaching an endpoint simply shortens the line.
4. Usage & Tips
Gap vs split. Enter after the first point for a clean split with no gap; click a second point to open a gap (e.g. a driveway through a curb line). Interior vertices. Because segmentation is vertex-preserving, intermediate polyline vertices survive the break exactly.
Changes a line's length by a delta, a percentage, or to an absolute total — the end you click is the end that moves. It is AutoCAD's Lengthen, the precise way to fine-tune a line to an exact length.
1. How It Works
The clicked end is identified, then the target length is computed by mode: delta → current + value, percent → current·value/100, total → value. If the target is shorter than the current length, the line is trimmed via line_substring; if longer, the terminal vertex is moved along the terminal segment's direction by the extra distance. Values are metres and remain metre-accurate in geographic projects.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Mode | Enum | Delta | Delta / Percent / Total | How the value is interpreted. |
| Value | Double | 5.0 | ±1 000 000 (min 0.001 for percent/total) | Delta (m), percent (%), or total length (m). |
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the line near the end to change. |
| 2 | Dialog | Choose mode + value; Apply. |
4. Output & Behaviour
The selected feature is modified in place. A target ≤ 1e-9 is rejected; empty or CRS-failed geometry is skipped. Shortening trims cleanly through interior vertices.
5. Usage & Tips
Which end moves. Click near the end you want changed; extension follows the terminal segment direction. Negative delta. A negative delta shortens the line from the clicked end. Total length. The total mode is the quickest way to normalise a set of lines to a common length.
Moves, rotates, and optionally scales a feature using source→destination point pairs. It is AutoCAD's Align: match two points to translate-and-rotate, or match one point to move without rotating.
1. How It Works
One source→destination pair applies a pure translation. Two pairs derive a rotation from the difference of the two direction vectors and, when scaling is enabled, a factor target_length / source_length. The full transformation is composed into a single QTransform(m11, m12, m21, m22, dx, dy) — pre-translate by −src1, rotate/scale, then translate by +dst1 — and applied through one affine transform, so curves and Z/M values survive intact. Degenerate source lengths (≤ 1e-12) are rejected.
2. Parameters
| Parameter | Type | Default | Description |
| Scale to match destination | Checkbox | False | When on, scale by the destination/source pair-length ratio. |
3. Interaction
| Step | Input | Result |
| 0 | Dialog | (Optionally) enable scaling; Start. |
| 1 | Left-click | Pick the feature. |
| 2–3 | Left-click ×2 | Source point 1, destination point 1. |
| 4–5 | Left-click ×2 | Source point 2, destination point 2 — aligned. (Enter after pair 1 = move only.) |
4. Output & Behaviour
The selected feature is modified in place. Precision input is supported for the point picks.
5. Usage & Tips
Move-only. Press Enter after the first pair to translate without rotating. Rubber-sheeting one feature. With scaling on, Align maps one feature onto another's footprint in one step — the CAD equivalent of a two-point registration. Curves preserved. Because the whole operation is a single affine transform, CircularString/CompoundCurve and Z/M data are not flattened.
Moves only the vertices caught by a crossing window, across every editable layer the window intersects, in one operation. It is AutoCAD's Stretch — grab a corner of a drawing and pull, without disturbing the vertices outside the selection.
1. How It Works
Two opposite clicks define the crossing window. The tool iterates every editable vector layer, transforms the window into each layer's CRS, and selects features that intersect it. For each selected feature it iterates the geometry's vertices and applies moveVertex(point + (dx, dy)) only to vertices inside the window. Edits are grouped per layer and applied with changeGeometry in a per-layer edit command. Polygon rings stay closed, and a failed write rolls back all edited layers.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | First window corner. |
| 2 | Left-click | Opposite window corner. |
| 3 | Left-click | Base point. |
| 4 | Left-click | Target point — vertices inside the window move by (dx, dy). |
3. Output & Behaviour
Vertices of one or more features move, potentially across multiple layers. A zero-area window or a window that crosses no editable feature is rejected. Polygon rings remain closed, so areas stay valid.
4. Usage & Tips
Crossing-window semantics. Only vertices inside the window move; edges straddling the boundary stretch. This is the key difference from Move, which translates a whole feature. Multi-layer. Stretch is the one tool that edits several layers at once — useful for pulling a shared corner across a road platform and a parcel boundary simultaneously.
Splits a feature into its single parts, or a line/polygon boundary into single two-point segments, optionally removing the source. It is AutoCAD's Explode — break a compound feature down into its atomic pieces.
1. How It Works
In parts mode, a multipart feature is decomposed via asGeometryCollection(). In segments mode, polygon rings and lines are broken into two-point segments (skipping zero-length segments ≤ 1e-12). Pieces that match the source layer's geometry type are added to the same layer; otherwise they go to the managed planx_explode line layer (because a polygon layer cannot hold segment lines). If remove source is on, the original is deleted.
2. Parameters
| Parameter | Type | Default | Options | Description |
| Mode | Enum | Multipart to parts | Parts / Segments | Decompose into single parts or single segments. |
| Remove source | Checkbox | True | — | Delete the original feature after exploding. |
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature. |
| 2 | Dialog | Choose mode + source removal; Apply. |
4. Output & Behaviour
Pieces land on the source layer (or planx_explode for cross-type segment output). A single-part feature cannot be split in parts mode; polygon segments always route to the managed line layer.
5. Usage & Tips
Boundary to edges. Explode a polygon in segments mode to obtain its individual boundary edges for separate manipulation. Keep the original. Untick "remove source" to keep the original alongside the pieces.
Creates a metre-accurate buffer polygon around any readable feature into a managed planx_buffer layer. It is the CAD tool for setback envelopes, protection zones, and clearance polygons — without touching the source layer.
1. How It Works
The feature is transformed to a local metric CRS, buffered with buffer(distance, segments, Qgis.EndCapStyle.Round, join_enum, 2.0) (miter limit 2.0), transformed back, and written to planx_buffer with source_layer, buffer_distance, and join_style attributes. The source only needs to be readable (require_editable = False).
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Buffer distance | Double | 5.0 m | 0.01 – 100 000 | Radius of the buffer polygon. |
| Join style | Enum | Round | Round / Bevel / Miter | Corner treatment at vertices. |
| Segments | Integer | 16 | 4 – 128 | Segments per quadrant of the round join. |
3. Interaction
| Step | Input | Result |
| 1 | Dialog | Set distance, join style, segments; Apply. |
| 2 | Left-click | Pick the feature to buffer. |
4. Output & Behaviour
Output goes to the managed planx_buffer layer (Polygon):
| Field | Type | Description |
| source_layer | string | Name of the source layer. |
| buffer_distance | double | The applied buffer distance. |
| join_style | string | round / bevel / miter. |
5. Usage & Tips
Separation of concerns. Buffers never write to the source layer, so a protection zone can be regenerated or discarded without risk to the source geometry. Geographic accuracy. The local metric CRS keeps a "5 m" buffer a true 5 m even in EPSG:4326.
Fills a polygon with clipped hatch line geometry — parallel, cross, or diagonal patterns — into a managed planx_hatch layer. It is the CAD hatch that produces real (exportable) line geometry rather than a symbol fill.
1. How It Works
In a local metric CRS the tool computes the polygon's bounding-box diagonal (diag = hypot(w, h)·1.2 + spacing·2) and the number of candidate lines (n_steps = int(diag/spacing) + 2), refusing when 2·n_steps + 1 > 20 000. Parallel lines are generated across the box at the chosen angle(s) and each is clipped against the polygon with line.intersection(polygon); multi-line results are split to single parts. Angles map as parallel → [angle], diag_up → [45°], diag_down → [−45°], cross → [angle, angle+90°].
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Pattern | Enum | Parallel lines | Parallel / Cross / Diagonal up / Diagonal down | Hatch pattern family. |
| Spacing | Double | 2.0 m | 0.01 – 1 000 000 | Distance between hatch lines. |
| Angle | Double | 45.0° | −180 – 180 | Hatch line angle. |
| Colour | Color | #1a237e | any | Hatch line colour. |
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick a closed polygon (a non-multipart polyline is closed automatically). |
| 2 | Dialog | Set pattern, spacing, angle, colour; Apply. |
4. Output & Behaviour
Clipped lines go to the managed planx_hatch layer (LineString):
| Field | Type | Description |
| source_layer | string | Name of the hatched layer. |
| pattern | string | parallel / cross / diag_up / diag_down. |
| spacing_m | double | Line spacing in metres. |
| angle_deg | double | Line angle in degrees. |
| color | string | Hatch colour. |
5. Usage & Tips
Export-safe. Hatch lines are real geometry, so they survive export to CAD/GIS formats that lack symbol-level fills. Large areas. The 20 000-line cap prevents runaway generation on a huge polygon at tiny spacing — raise spacing or hatch a sub-area instead.
Splits a line into N equal-length segments, or generates the division point markers. It is AutoCAD's Divide/Measure — the precise way to partition an edge into equal parts.
1. How It Works
Cumulative distances are computed per part. In split mode, seg_len = total/N and each boundary is located with interpolate(), preserving interior vertices; the first segment replaces the source feature and the rest are added with copied attributes. In points mode, points are placed at interpolate(i·seg_len) for i = 1…N−1, written to the active point layer or the managed planx_divisions layer. Parts with fewer than two vertices are dropped and zero-length lines (≤ 1e-6) are rejected.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Segments | Integer | 3 | 2 – 10 000 | Number of equal parts. |
| Method | Enum | Split Line | Split Line / Create Points | Output segments or point markers. |
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the line. |
| 2 | Dialog | Set segments + method; Apply. |
4. Output & Behaviour
Split mode edits the source layer (first segment replaces the feature; the rest are added). Points mode writes to the active point layer or planx_divisions (Point, field source_fid).
5. Usage & Tips
Equal parts. Divide is length-equal subdivision — use
Break to split at a specific point instead.
Vertex preservation. Interior vertices survive the split, so a divided polyline keeps its original shape.
Welds multiple separately selected line segments into one continuous polyline (or several) within a gap tolerance. It is AutoCAD's Join — stitch touching segments back into a single feature.
1. How It Works
Segments are added by left-click; right-click or Enter joins. The join algorithm iteratively welds paths whose endpoints fall within the tolerance, checking all four endpoint-pair cases (A-end–B-start, A-end–B-end, A-start–B-start, A-start–B-end). The first selected feature is updated in place (changeGeometry) and the others are deleted (deleteFeatures) in one PlanX CAD: join lines edit command.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Join tolerance | Double | 1.0 m | 0.0 – 1000 | Maximum endpoint gap bridged by the weld. |
3. Interaction
| Step | Input | Result |
| 1 | Dialog | Enter join tolerance. |
| 2 | Left-click ×n | Add segments (must be from the same layer). |
| 3 | Right-click / Enter | Weld the segments. |
4. Output & Behaviour
A merged feature occupies the first selected feature's slot; the other source features are deleted. Line/polyline only; at least two lines from the same layer are required; if no endpoints match, an error is reported.
5. Usage & Tips
Gap bridging. The tolerance closes small drafting gaps, so slightly separated segments still weld. Order independence. Selection order is irrelevant to the result — the weld follows endpoint proximity, not click order.
Inserts, moves, and deletes vertices on polylines and polygons via on-canvas handles. It is the fine-grained node editor — the tool for nudging geometry that no whole-feature transform can reach.
1. How It Works
After a line/polygon is picked, an orange box handle (QgsVertexMarker, icon size 9) renders on every vertex, each tracked by (part_idx, vertex_idx). Dragging a handle moves it via moveVertex(); clicking on an edge inserts a vertex via closestSegmentWithContext + insertVertex(); right-clicking a handle deletes it via deleteVertex(). Multipart-safe through a linear vertex index computed from ring sizes. Deletes are refused when a ring would fall below its minimum — 2 vertices for a line, 4 for a closed polygon ring.
2. Interaction
| Input | Action |
| Drag a handle | Move that vertex (committed on release). |
| Click on an edge | Insert a new vertex there. |
| Right-click a handle | Delete that vertex. |
| Esc | Finish editing. |
3. Output & Behaviour
The selected feature is edited in place. Line/polygon geometry only. The handle hit-tolerance is 10 px; the insert tolerance is 8 px.
4. Usage & Tips
Ring integrity. Deletion is blocked before it can break a polygon ring below 4 vertices, so a polygon stays a valid area. Fine correction. Use Vertex Edit after snapping to fix the last few nodes a transform cannot; it is slower than Stretch but exact.
Six affine-transformation tools for positioning geometry. Every transform is multipart-, curve-, and Z/M-safe — holes, multi-rings, CircularString/CompoundCurve geometry, elevations, and measures survive, because each operation composes into a single QTransform or a metric-CRS rotation rather than a per-vertex rewrite.
Moves a feature from its picked base point to a target point by a pure translation. It is the most fundamental transform — and the one every other transform builds on.
1. How It Works
The picked base point and the target point define dx, dy; the geometry is translated with QgsGeometry.translate(dx, dy) and applied through the shared edit machinery.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature (this click is the base point). |
| 2 | Left-click | Target point — feature moves by the delta. |
3. Output & Behaviour
The selected feature is modified in place. Precision input is supported (@dx,dy or a bare distance along the cursor bearing).
4. Usage & Tips
Precision delta. Type
@10,0 after picking to move exactly 10 m east.
Copy instead of move. Use
Copy when the original should remain.
Duplicates a feature from its picked base point to a target point. Identical to Move except the original is preserved and a new feature (with copied attributes) is added.
1. How It Works
The base→target delta is applied with QgsGeometry.translate(dx, dy) and the result is added as a new feature with attributes copied from the source.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature (base point). |
| 2 | Left-click | Target point — a copy is placed there. |
3. Output & Behaviour
A new feature is added to the source layer; the original is untouched. Precision input is supported.
4. Usage & Tips
Repetitive placement. For regular repetitions use
Array; for a single offset duplicate, Copy is faster.
Attribute inheritance. The copy carries the source's attribute values.
Rotates a feature around a picked centre by a reference-to-target angle. Holding Ctrl snaps the rotation to 90° increments; a bare angle can be typed for exact rotation.
1. How It Works
The picked feature's centre is the rotation centre. The reference direction and target direction are measured with atan2 in a local metric CRS, and the rotation is target_angle − ref_angle. When Ctrl is held the rotation snaps to round(rotation/90)·90. The geometry is rotated with rotate_geometry(geom, center, −rotation, crs), computed in the local metric CRS for metre-accurate angular behaviour in any project CRS.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature (rotation centre). |
| 2 | Left-click | Reference direction. |
| 3 | Left-click | Target angle — rotation committed. |
3. Output & Behaviour
The selected feature is modified in place. Precision input accepts a signed angle in degrees.
4. Usage & Tips
Right-angle snap. Hold Ctrl to snap to 90° increments for clean orthogonal layout. Exact angle. Type a bare signed number (e.g. 45 or -30) to rotate by a precise angle.
Scales a feature around a picked centre by a reference-distance→target-distance ratio. A positive factor can be typed for exact uniform scaling.
1. How It Works
The factor is target_distance / ref_distance (a reference distance below 0.001 is rejected as too small). Scaling composes into a single QTransform:
QTransform(factor, 0, 0, factor, cx(1−factor), cy(1−factor))
The transform preserves curves and Z/M values. Precision input accepts a positive factor.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature (scale centre). |
| 2 | Left-click | Reference distance point. |
| 3 | Left-click | Target distance point — scale committed. |
3. Output & Behaviour
The selected feature is scaled in place. The factor must be positive and finite; a reference distance < 0.001 is refused.
4. Usage & Tips
Uniform factor. Type a number (e.g.
0.5) for exact uniform scaling around the picked centre.
Non-uniform? Scale is uniform only; non-uniform stretch is what
Stretch does.
Mirrors a copy of a feature across a two-point axis, leaving the original untouched. It is AutoCAD's Mirror — reflect geometry across a construction axis while keeping the source.
1. How It Works
The reflection is computed in a local metric CRS from the normalised axis direction (ux, uy):
m11 = 2ux² − 1, m12 = m21 = 2uxuy, m22 = 2uy² − 1, translation = start − m·start
The result is added as a mirrored copy with copied attributes; the source is never modified. A degenerate axis (zero length) produces no result.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature to mirror. |
| 2 | Left-click | Axis start point. |
| 3 | Left-click | Axis end point — mirrored copy added. |
3. Output & Behaviour
A mirrored copy is added to the source layer; the original is unchanged.
4. Usage & Tips
Axis accuracy. Validate the axis direction before confirming — a mirrored planning layout that is slightly off-axis is hard to notice and hard to undo after the fact. Symmetry. Mirror is the fastest way to produce a symmetric counterpart (e.g. the second side of a road cross-section).
5. Literature
The reflection matrix is the standard affine form in Farin (2002) and Schneider & Eberly, Geometric Tools for Computer Graphics. Full citations in the references appendix.
Duplicates a selected feature in a rectangular grid or a polar (circular) array. It is AutoCAD's Array — the tool for repetitive layout that would be tedious and imprecise to copy by hand.
1. How It Works
Rectangular mode produces rows·cols − 1 copies, each translate(c·dx, r·dy). Polar mode rotates the feature around a centre: step_angle = sweep/count (full circle) or sweep/max(count−1, 1), each copy rotate_geometry(geom, center, angle). A full circle does not duplicate the source at angle 0 (the source stays in place). Requests exceeding MAX_ARRAY_COPIES = 10 000 are refused. Polar mode shows a live combined preview via unaryUnion().
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Mode | Enum | Rectangular | Rectangular / Polar | Array family. |
| Rows / Columns | Integer | 3 / 3 | 1 – 500 each | Rectangular grid dimensions. |
| Δx / Δy | Double | 10.0 m | −1e6 – 1e6 | Column / row spacing. |
| Copies | Integer | 6 | 2 – 360 | Polar copy count. |
| Total sweep | Double | 360.0° | −360 – 360 | Polar sweep angle. |
3. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick the feature. |
| 2 | Dialog | Set mode + parameters; Generate. |
| 3 | Left-click | Polar only — click the array centre. |
4. Output & Behaviour
Copies are added to the source layer with copied attributes. The 10 000-copy cap guards against accidental runaway arrays.
5. Usage & Tips
Tree grids. Rectangular array with Δx=Δy produces a street-tree or column grid in one step. Roundabouts. Polar array distributes features evenly around a centre. Full vs partial. A sweep of exactly 360° is a full circle (no duplicate at 0°); a partial sweep spaces copies across the arc.
Five tools for verification and annotation. Distance and Area measure live on the canvas; Measure Selection reports the length/area of a picked feature; Dimension writes a persistent, labelled dimension line. All length/area values use the project CRS and ellipsoid, so they are geodetically correct.
Live on-canvas distance measurement along a multi-point path, with a snap-aware running total. It answers "how far is it, along the way?" without creating any geometry.
1. How It Works
Points accumulate on the canvas; each is snapped. The distance is computed with QgsDistanceArea configured to the project CRS and ellipsoid (setSourceCrs + setEllipsoid), so measurement follows the ellipsoid rather than raw canvas units. A live rubber-band polyline previews the path; the result is shown in a message bar.
2. Interaction
| Input | Action |
| Left-click | Add a point to the path (≥ 2 required). |
| Right-click / Enter | Finish and report the total distance. |
| Backspace | Undo the last point. |
| Esc | Cancel. |
3. Output & Behaviour
No geometry is written — the result is a message-bar total. The running total updates live as points are added.
4. Usage & Tips
Along the way. Use multi-point Distance for a route total; use
Measure Selection for a feature's stored length.
Snapping. Keep snapping on so each point locks to existing vertices for accurate totals.
Live on-canvas polygon area (and perimeter) measurement. It reports the area of a traced region on the fly, without writing a polygon feature.
1. How It Works
Points accumulate to trace a region; the ring is closed on move for the live preview. Area is computed with QgsDistanceArea (project CRS + ellipsoid) via measureArea; on finish the perimeter is also summed. Areas at or above 10 000 m² are formatted in hectares (area/10000).
2. Interaction
| Input | Action |
| Left-click | Add a vertex to the region (≥ 3 required). |
| Right-click / Enter | Finish and report area + perimeter. |
| Backspace | Undo the last vertex. |
| Esc | Cancel. |
3. Output & Behaviour
Message-bar result only; no geometry is created. Values switch from m² to hectares above the 10 000 m² threshold.
4. Usage & Tips
Quick parcel check. Trace a parcel to verify its area before committing a drawn boundary.
Persistent area. Use
Measure Selection for a stored polygon's area.
Reports the geodetic length of a picked line feature. It measures what is actually stored in the geometry — the authoritative length, not a traced approximation.
1. How It Works
A line feature is picked (read-only — no edit session needed). QgsDistanceArea is configured with the layer's CRS and the project ellipsoid, and measureLength returns the length, shown in a message box.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick a line feature — length reported. |
3. Output & Behaviour
Message-box result only. Line mode requires a line feature.
4. Usage & Tips
Authoritative length. Prefer this over traced Distance when the feature already exists — it measures the stored geometry exactly.
Reports the geodetic area and perimeter of a picked polygon feature. It is the authoritative area check for a stored parcel, block, or building footprint.
1. How It Works
A polygon feature is picked. QgsDistanceArea is configured with the layer CRS and project ellipsoid; measureArea and measurePerimeter return the values, with the area converted to hectares (/10000) for readability.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | Pick a polygon feature — area + perimeter reported. |
3. Output & Behaviour
Message-box result only. Polygon mode requires a polygon feature.
4. Usage & Tips
Parcel audit. Verify a subdivided parcel's area against the expected value before finalising a plan. Perimeter. Both area and perimeter are reported, covering the common deliverable fields.
Creates a persistent, labelled linear dimension line between two clicked points on a managed planx_dimensions layer. It is the CAD dimension — a distance annotation that stays on the plan, not a transient measurement.
1. How It Works
Two clicks define the measured span. The distance is computed with QgsDistanceArea.measureLine in the project CRS/ellipsoid and formatted (≥ 1000 m → km, else metres). A LineString is written to planx_dimensions and QGIS labelling is enabled once on the label field (text size 10, colour #1a237e). The tool stays active for consecutive dimensions.
2. Interaction
| Step | Input | Result |
| 1 | Left-click | First dimension point. |
| 2 | Left-click | Second point — dimension committed, tool continues. |
| — | Right-click | Reset. |
| — | Esc | Cancel. |
3. Output & Behaviour
Dimension lines land on the managed planx_dimensions layer (LineString):
| Field | Type | Description |
| distance_m | double | Measured distance in metres. |
| label | string | Formatted label (m or km). |
| from_x, from_y | double | First point coordinates. |
| to_x, to_y | double | Second point coordinates. |
4. Usage & Tips
Auditability. A persistent dimension feature is a deliverable asset — reviewers can re-measure it against the geometry. Separation. Dimensions live on their own layer, so they can be toggled or exported independently of the drawing.
Three tools written specifically for the planning workflow: a parametric road-platform generator, a junction topology solver, and a one-click block-corner chamfer. They turn the drawing primitives of groups 01–04 into complete road geometry — the tools a city planner reaches for weekly.
Sketches a road centreline and generates the full platform — centreline, lanes, median, and sidewalks — into a managed planx_road_platform layer. It is the parametric road cross-section: configure the section once, draw the axis, and receive all the platform linework.
1. How It Works
Parameters are collected first, then the centreline is sketched on the canvas (left-click adds vertices, right-click/Enter finishes). RoadGenerator.generate() transforms the centreline to a local metric CRS so every offset is in true metres, writes the centerline component first, then emits lanes, median edges, and sidewalks by offsetting the centreline on the appropriate side(s). The total width is derived from the cross-section:
total_width = direction_factor · lane_count · lane_width + (median unless one-way) + left_sidewalk + right_sidewalk
direction_factor = 2 (two-way) or 1 (one-way)
One-way platforms offset lane_count + 1 lane lines across the platform width; two-way platforms emit a median pair (when the median width is positive) plus lane_count lane lines per side, then sidewalks at the outer road edge. Each feature is tagged with component, side, lane number, widths, and a visibility flag so a styling can later distinguish road edges from construction lines.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Road type | Enum | Vehicular | Vehicular / Pedestrian / Bicycle / Collector / Arterial | Road classification (stored in road_type). |
| Traffic direction | Enum | Two-way | Two-way / One-way | Whether lanes are generated on both sides or one. |
| Lane count | Integer | 2 | 1 – 8 (per direction) | Number of lanes per direction. |
| Lane width | Double | 3.50 m | 2.0 – 10.0 (step 0.25) | Width of each lane. |
| Median width | Double | 2.00 m | 0.0 – 20.0 (step 0.50) | Central median (disabled for one-way). |
| Left sidewalk | Double | 2.00 m | 0.0 – 10.0 (step 0.50) | Left sidewalk width. |
| Right sidewalk | Double | 2.00 m | 0.0 – 10.0 (step 0.50) | Right sidewalk width. |
A live total-width readout recomputes on every dimension or direction change.
3. Output & Behaviour
Output goes to the managed planx_road_platform layer (MultiLineString) with 11 fields:
| Field | Type | Description |
| road_id | int | Auto-incremented road identifier (max + 1). |
| road_type | string | Vehicular / Pedestrian / Bicycle / Collector / Arterial. |
| component | string | centerline / lane / median / sidewalk. |
| side | string | left / right / center / none. |
| lane_no | int | Lane index (0 for the centreline). |
| lane_count | int | Lanes per direction. |
| lane_width | double | Configured lane width (m). |
| median_width | double | Configured median width (m). |
| sidewalk_width | double | Sidewalk width for the feature (m). |
| total_width | double | Total platform width (m). |
| visible | int | 1 for road edges/sidewalks (styleable), 0 for construction lines. |
4. Usage & Tips
Centreline quality. Start from a clean centreline (use Polyline) and let snapping lock it to junctions.
Visibility flag. The
visible field separates drawable road edges from auxiliary construction lines, so a styling rule can hide the latter.
Junction next. Generate roads first, then resolve intersections with the
Junction Solver.
Resolves a road junction by trimming platform components within an impact radius, solving curb corners with a straight chamfer or tangent fillet at the true support-line intersection, closing median arms, and optionally creating a round or teardrop traffic island — all as one rollback-safe operation.
1. The Five-Phase Algorithm
The solver is a pure-geometry module (urban/junction_geometry.py) operating on curb half-edges:
- Half-edge extraction. A circular buffer (impact radius, 48 segments) is drawn at the junction centre and intersected with road-platform features. Outward curb rays (
CurbHalfEdge) are extracted from sidewalk components; median components are collected separately for caps.
- Approach clustering. Half-edges are grouped by
road_id, sorted by angle, and clustered within an angular tolerance (default 12°) with a wrap-around merge across 0°/360°; clusters with fewer than two distinct curbs are dropped. Each cluster becomes an Approach with a signed left/right curb.
- Sector pairing. Each approach's left curb is paired with the next (counter-clockwise) approach's right curb. Sectors whose directed sweep ≥
π − 1e-7 are skipped — a straight-through or reflex gap is not a local corner.
- Corner solving. The true intersection of the two support lines is found (
support_line_intersection). A chamfer extends the cutback distance along each ray and connects with a straight line; a fillet uses the same tangent-circle construction as the Fillet tool (r/tan(θ/2), r/sin(θ/2), 16-segment arc with endpoints snapped to the exact cut points).
- Application. Non-sidewalk components are trimmed with an annular trim, sidewalk curbs are trimmed at the solved cut points, connection features are written (
junction_chamfer/junction_fillet, road_type="junction"), median caps are added, and the island is created.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Impact radius | Double | 12.0 m | 3.0 – 100.0 | Radius of the area affected around the junction centre. |
| Solution type | Enum | Straight Chamfer | Straight Chamfer / Tangent Fillet | Corner resolution style. |
| Chamfer distance | Double | 5.0 m | 0.5 – 50.0 | Setback along each ray (chamfer mode). |
| Fillet radius | Double | 3.0 m | 0.5 – 50.0 | Tangent-arc radius (fillet mode). |
| Island type | Enum | Round | None / Round / Teardrop | Traffic-island shape. |
| Island radius | Double | 3.0 m | 0.5 – 30.0 | Island radius (round/teardrop). |
| Teardrop length | Double | 6.0 m | 1.0 – 50.0 | Teardrop elongation (teardrop only). |
3. Output & Behaviour
Trimmed features and new connection features are written to planx_road_platform; islands are written to planx_junction_islands (Polygon, fields junction_id, island_type, island_radius). All road edits and island edits are kept in one atomic rollback unit — the road is committed only after the island succeeds, and a committed island is compensated if the road later fails.
4. Usage & Tips
Generate first, solve second. Run the Road Platform Generator, then click each junction centre. Chamfer vs fillet. A straight chamfer reads as a kerb-return for low-speed streets; a tangent fillet reads as a smoother turning radius. Islands. A round or teardrop island is created only when an island type is selected — leave it at None for a plain intersection.
5. Literature
The half-edge data structure and angular clustering follow the computational-geometry treatment in de Berg et al. (2008); the tangent-circle corner solver is the same construction documented under Fillet. Full citations in the references appendix.
Resolves an urban block corner where two outer curb lines intersect, with a straight setback or a curved tangent fillet, and optionally removes short remnant segments. It is a one-click-per-corner tool designed for block-corner rounding across a plan, scanning all project line layers rather than a single active layer.
1. How It Works
The tool searches all project line layers for features within tolerance·3 of the click, finds the nearest intersecting pair (a true intersection, or a virtual one when the gap is within tolerance). Straight mode trims both lines by the distance and connects the cut points with a straight segment; curved mode uses the shared create_fillet_and_trims to trim to the tangent points and connect with a fillet arc. The connector inherits the first line's attributes. A cleanup pass deletes sub-threshold remnant segments within tolerance·5, restricted to the two source layers and excluding the connector. The tool repeats (click → result → click) until right-click/Esc.
2. Parameters
| Parameter | Type | Default | Constraints | Description |
| Corner mode | Enum | Curved (Tangent Fillet) | Curved / Straight | Fillet arc vs straight setback. |
| Distance | Double | 5.0 m | 0.5 – 50.0 | Arc radius (curved) or setback (straight). |
| Search tolerance | Double | 0.5 m | 0.01 – 5.0 | Intersection search tolerance around the click. |
| Remnant cleanup | Double | 1.0 m | 0.0 – 20.0 | Remove remnant segments shorter than this. |
3. Output & Behaviour
The two curb lines are trimmed and a connector (line or arc) is added, inheriting the first line's attributes. Edits preserve an existing user edit session. Remnant cleanup removes short leftover segments near the resolved corner.
4. Usage & Tips
Block chamfer vs general Chamfer. The general
Chamfer is a two-line AutoCAD-parity command on the active layer with two cutback distances; Block Chamfer is a dialog-driven urban tool with one distance/radius, a search tolerance, a cleanup pass, and it scans all project lines. Use Block Chamfer for block-corner rounding, Chamfer for a plain two-line corner cut.
Sequential corners. The tool stays active, so one click resolves each corner in turn.
Command Line & Aliases
The dock's search box is a full AutoCAD-style command line. Every tool is reachable by an alias, an exact tool key, or a fuzzy name match — and an empty Enter repeats the last command. This is the fastest path through the plugin for muscle-memory CAD users.
Resolution precedence
alias → exact tool key → fuzzy search-term match (then: "Unknown command")
Full command reference
| Tool | Aliases | Shortcut |
| Line | l line | Ctrl+Shift+L |
| Polyline | pl pline polyline | Ctrl+Shift+P |
| Rectangle | rec rectang rectangle | Ctrl+Shift+R |
| Polygon | pol polygon | Ctrl+Shift+G |
| Circle | c circle | Ctrl+Shift+C |
| Arc | a arc | Ctrl+Shift+A |
| Construction Infinite | xl xline construction | Ctrl+Shift+K |
| Construction Ray | ray | Ctrl+Alt+K |
| Construction Segment | seg | Ctrl+Alt+L |
| Offset | o offset | Ctrl+Shift+O |
| Multi-Offset | mo moff | Ctrl+Shift+X |
| Trim | tr trim | Ctrl+Shift+T |
| Extend | ex extend | Ctrl+Shift+E |
| Fillet | f fillet | Ctrl+Shift+F |
| Chamfer | cha chamfer | — |
| Break | br break | — |
| Lengthen | len lengthen | — |
| Align | al align | — |
| Stretch | s stretch | — |
| Explode | x explode | — |
| Buffer | b buffer | Ctrl+Shift+B |
| Hatch | h hatch | Ctrl+Shift+H |
| Divide | div divide | Ctrl+Shift+U |
| Join | j join | Ctrl+Shift+J |
| Vertex Edit | ve vertex | Ctrl+Shift+V |
| Move | m move | Ctrl+Shift+M |
| Copy | co cp copy | — |
| Rotate | ro rotate | — |
| Scale | sc scale | — |
| Mirror | mi mirror | — |
| Array | ar array | Ctrl+Shift+Y |
| Distance | di dist measure | Ctrl+Shift+I |
| Area | aa area | — |
| Measure Selection (Line) | msl measureline | — |
| Measure Selection (Area) | msa measurearea | — |
| Dimension | dim dimension | Ctrl+Shift+D |
| Road Platform Generator | road | — |
| Junction Solver | junction | — |
| Block Chamfer | block blockchamfer | — |
Command loop. An empty Enter first tries to finish an in-progress sketch, then repeats the last tool (__repeat__). ↑/↓ recall a 50-entry history (consecutive duplicates skipped). Ctrl+Shift+Space repeats the last tool instantly; Ctrl+Shift+S focuses the command line. Autocomplete is a case-insensitive QCompleter over all aliases and tool keys. Unknown commands echo a clear message rather than failing silently.
Managed Layer System
Output tools write to plugin-managed memory layers rather than the user's active layer. Each layer is created on first use and reused across the session by matching name, geometry type, CRS, and field schema.
| Layer | Geometry | Created by | Key fields |
| planx_buffer | Polygon | Buffer | source_layer, buffer_distance, join_style |
| planx_construction | LineString | Construction Line | mode, from_x, from_y, to_x, to_y |
| planx_dimensions | LineString | Dimension | distance_m, label, from_x, from_y, to_x, to_y |
| planx_hatch | LineString | Hatch | source_layer, pattern, spacing_m, angle_deg, color |
| planx_divisions | Point | Divide (points) | source_fid |
| planx_explode | LineString | Explode (cross-type) | copied source attributes |
| planx_road_platform | MultiLineString | Road, Junction | road_id, road_type, component, side, lane_no, lane_count, lane_width, median_width, sidewalk_width, total_width, visible |
| planx_junction_islands | Polygon | Junction (islands) | junction_id, island_type, island_radius |
Managed layers declare their schema in the provider URI (integer/double/string/long field types), which removes the last Qt5-era QVariant usage from the plugin and keeps the memory layers compatible with QGIS 4/Qt6 while retaining the QGIS 3.28 LTR floor.
CRS Safety
Distance-based CAD operations are meaningless in angular coordinate systems (Farin 2002). Every metric operation — precision input, offset, fillet, chamfer, buffer, hatch, rotate, mirror, road generation, junction solving — resolves through a local metric work CRS so distances are true metres regardless of the project CRS.
geographic = WGS84 transform of the work point;
if latitude ∈ [−80°, 84°]: zone = clamp(1..60, floor((lon+180)/6) + 1), EPSG = 32600/32700 + zone;
else: Azimuthal Equidistant (AEQD) on WGS84, centred on the work point, units = m.
The work point is clamped to valid longitude/latitude ranges before the zone is computed. Each operation derives its own CRS from its own work location, so even operations far apart in a project receive the appropriate UTM zone. Polar regions fall back to an azimuthal-equidistant projection, which preserves distances and angles from the centre.
Edit-Session Safety
Every geometry-modifying operation runs inside QGIS edit commands (beginEditCommand/endEditCommand) for transactional safety with rollback on failure. Multi-layer operations — Fillet, Chamfer, Junction — open edit commands on all involved layers and commit only if every step succeeds; the Junction solver keeps a single rollback unit across its trims, corner connections, and island creation.
- Session preservation. Tools that write to managed layers check
layer.isEditable() before starting their own session; if the user is already editing, the existing session is used without auto-commit.
- Auto-start. Drawing tools auto-start editing if the target layer is not yet editable.
- Single-part layers. Operations that would produce disconnected results (Trim, Divide) replace the original with the first part and add the rest as new features with copied attributes.
- Rollback. A failed write rolls back all edited layers — no half-applied geometry is left behind.
Snapping & Picking
The plugin uses two distinct picking models. Drawing tools defer entirely to QGIS's native QgsSnappingUtils.snapToMap(), so they honour the project's snapping configuration without a plugin-side tolerance. Modify/transform tools use an explicit pick aperture with self-pick protection:
PICK_TOLERANCE = 10 px; search box = point ± mapUnitsPerPixel()·10
candidate acceptance: geometry.distance(click) ≤ max(rect.width, rect.height)/2
The aperture is enforced on true geometry distance, not just bounding-box overlap, closing the classic bbox-only pick bug. Two-step tools (Trim, Extend, Fillet, Chamfer) exclude the first picked feature from the second pick, so a feature cannot operate on itself. Vertex Edit uses an 8 px insert tolerance and a 10 px handle hit-tolerance.
Keyboard Shortcuts
Twenty-three tools have application-wide shortcuts (Ctrl+Shift combinations avoid common QGIS bindings); the remaining commands are alias-only. A full shortcut guide is available in-app via Ctrl+Shift+/.
| Tool | Shortcut | Tool | Shortcut |
| Line | Ctrl+Shift+L | Hatch | Ctrl+Shift+H |
| Polyline | Ctrl+Shift+P | Construction Infinite | Ctrl+Shift+K |
| Rectangle | Ctrl+Shift+R | Construction Ray | Ctrl+Alt+K |
| Polygon | Ctrl+Shift+G | Construction Segment | Ctrl+Alt+L |
| Circle | Ctrl+Shift+C | Dimension | Ctrl+Shift+D |
| Arc | Ctrl+Shift+A | Distance | Ctrl+Shift+I |
| Offset | Ctrl+Shift+O | Divide | Ctrl+Shift+U |
| Trim | Ctrl+Shift+T | Multi-Offset | Ctrl+Shift+X |
| Extend | Ctrl+Shift+E | Join | Ctrl+Shift+J |
| Fillet | Ctrl+Shift+F | Repeat Last Tool | Ctrl+Shift+Space |
| Buffer | Ctrl+Shift+B | Focus Tool Search | Ctrl+Shift+S |
| Move | Ctrl+Shift+M | Vertex Edit | Ctrl+Shift+V |
| Array | Ctrl+Shift+Y | Shortcut Guide | Ctrl+Shift+/ |
Command-line-only tools: Chamfer, Break, Lengthen, Align, Stretch, Explode, Copy, Rotate, Scale, Mirror, Block Chamfer, Area, and the two Measure-Selection tools.
Academic References
The geometric methods in this plugin are drawn from the peer-reviewed computational-geometry and computer-graphics literature. Where a construction admits multiple implementations, the plugin documents which variant is used in the tool's own entry.
- Farin, G. (2002). Curves and Surfaces for CAGD: A Practical Guide (5th ed.). Morgan Kaufmann. DOI: 10.1016/B978-1-55860-737-8.X5000-5
- de Berg, M., Cheong, O., van Kreveld, M., & Overmars, M. (2008). Computational Geometry: Algorithms and Applications (3rd ed.). Springer. DOI: 10.1007/978-3-540-77974-2
- O'Rourke, J. (1998). Computational Geometry in C (2nd ed.). Cambridge University Press. DOI: 10.1017/CBO9780511804120
- Preparata, F. P., & Shamos, M. I. (1985). Computational Geometry: An Introduction. Springer. ISBN 978-0387961316.
- Goldman, R. (2003). Pyramid Algorithms: A Dynamic Programming Approach to Curves and Surfaces for Geometric Modeling. Morgan Kaufmann. DOI: 10.1016/B978-1-55860-354-7.X5000-3
- Glassner, A. S. (Ed.). (1990). Graphics Gems. Academic Press. DOI: 10.1016/C2009-0-22266-2
- Schneider, P. J., & Eberly, D. H. (2003). Geometric Tools for Computer Graphics. Morgan Kaufmann. ISBN 978-1558605947.
- Faux, I. D., & Pratt, M. J. (1979). Computational Geometry for Design and Manufacture. Ellis Horwood. ISBN 978-0853121145.
- Mäntylä, M. (1988). An Introduction to Solid Modeling. Computer Science Press. ISBN 978-0881751086.
- Piegl, L., & Tiller, W. (1997). The NURBS Book (2nd ed.). Springer. ISBN 978-3540615453.
- Douglas, D. H., & Peucker, T. K. (1973). Algorithms for the reduction of the number of points required to represent a digitized line or its caricature. Cartographica, 10(2), 112–122. DOI: 10.3138/FM57-6770-U75U-7727
- Snyder, J. P. (1987). Map Projections—A Working Manual (USGS Professional Paper 1395). U.S. Government Printing Office. DOI: 10.3133/pp1395
- Eminoğlu, Y. (2025). PlanX CAD Toolset: An AutoCAD-style drafting workbench for QGIS. Zenodo. DOI: 10.5281/zenodo.20753127