diff --git a/crates/engine/src/cmd/curves.rs b/crates/engine/src/cmd/curves.rs
--- a/crates/engine/src/cmd/curves.rs
+++ b/crates/engine/src/cmd/curves.rs
@@ -479,6 +479,19 @@ impl Chain {
         }
         best.1
     }
+    /// The curve parameter of the point on the chain nearest `p`: the index of its segment plus
+    /// the fraction along it (AutoCAD's polyline parameter; 0..1 along a line or an arc).
+    pub fn param_of(&self, p: Vec2) -> f64 {
+        let mut best = (f64::INFINITY, 0.0);
+        for (i, s) in self.segs.iter().enumerate() {
+            let c = s.closest(p);
+            let dd = c.dist(p);
+            if dd < best.0 {
+                best = (dd, i as f64 + seg_param(s, c));
+            }
+        }
+        best.1
+    }
     /// Reversed copy.
     pub fn reversed(&self) -> Chain {
         Chain { segs: self.segs.iter().rev().map(Segment::reversed).collect(), closed: self.closed }
diff --git a/crates/engine/src/cmd/draw2/divide.rs b/crates/engine/src/cmd/draw2/divide.rs
--- a/crates/engine/src/cmd/draw2/divide.rs
+++ b/crates/engine/src/cmd/draw2/divide.rs
@@ -71,12 +71,24 @@ pub(super) fn run_measure(s: &mut Session, p: &Value) -> Result<Value> {
     }
     let block = str_param(p, "block").map(str::to_string);
     check_block(s, block.as_deref())?;
-    if let Some(from) = point_param(p, "from")
-        && !c.closed
-        && let (Some(a), Some(b)) = (c.start(), c.end())
-        && from.dist(b) < from.dist(a)
-    {
-        c = c.reversed();
+    // AutoCAD measures from the end the pick is nearer by the curve's parameter (segment index
+    // plus the fraction along it), not by distance: an open curve from its end once the pick is
+    // halfway or further, a closed one from its first vertex, backwards from halfway on. A
+    // circle always runs counterclockwise from angle 0.
+    if let Some(from) = point_param(p, "from") {
+        let past_half = match curves::entity(s, h)?.kind {
+            EntityKind::Circle(_) => false,
+            // A spline by its own parameter: its tessellation drops zero-length pieces, so the
+            // segment count is not the spline's parameter range.
+            EntityKind::Spline(sp) => {
+                let (lo, hi) = sp.domain();
+                curves::spline_param_of(&sp, from) >= (lo + hi) / 2.0
+            }
+            _ => c.param_of(from) >= c.segs.len() as f64 / 2.0,
+        };
+        if past_half {
+            c = c.reversed();
+        }
     }
     let pts = measure_points(&c, step);
     let hs = place_markers(s, &pts, block.as_deref(), bool_or(p, "align", true))?;
diff --git a/crates/engine/src/cmd/draw2/tests.rs b/crates/engine/src/cmd/draw2/tests.rs
--- a/crates/engine/src/cmd/draw2/tests.rs
+++ b/crates/engine/src/cmd/draw2/tests.rs
@@ -302,6 +302,193 @@ fn divide_and_measure_json() {
     assert!(s.execute("measure", &json!({"handle": l, "length": 1e-300})).is_err());
 }
 
+/// DIVIDE and MEASURE against the points AutoCAD 2024 places for the same object and pick
+/// (black-box: synthetic objects in accoreconsole, `(command "_.MEASURE" (list ename point) …)`,
+/// every POINT read back with `entget`). The pick chooses the end by the curve's parameter, not
+/// by distance; a closed polyline runs from its first vertex, a circle from angle 0.
+#[test]
+fn divide_and_measure_match_autocad() {
+    type Case = ((&'static str, serde_json::Value), &'static str, f64, [f64; 2], usize, &'static [[f64; 2]]);
+    // ((seed command, params), command, segments or length, pick, POINT count, AutoCAD points)
+    let cases: Vec<Case> = vec![
+        // DIVIDE-001: (list ename point).
+        (
+            ("arc", json!({"center": [0.0, 0.0], "radius": 20.0, "start": 30.0, "end": 250.0})),
+            "divide",
+            5.0,
+            [-2.090569265353071, 19.890437907365467],
+            4,
+            &[
+                [-19.021130325903, 6.180339887499],
+                [-17.975880925983, -8.767422935782],
+                [-9.389431255718, 17.658951857179],
+                [5.51274711634, 19.225233918766],
+            ],
+        ),
+        // DIVIDE-002: (list ename point).
+        (
+            ("circle", json!({"center": [0.0, 0.0], "radius": 15.0})),
+            "divide",
+            5.0,
+            [-4.63525491562421, 14.265847744427305],
+            5,
+            &[
+                [-12.135254915624, -8.816778784387],
+                [-12.135254915624, 8.816778784387],
+                [4.635254915624, -14.265847744427],
+                [4.635254915624, 14.265847744427],
+                [15.0, 0.0],
+            ],
+        ),
+        // MEASURE-016: (list ename point).
+        (
+            ("line", json!({"points": [[0.0, 0.0], [37.0, 13.0]]})),
+            "measure",
+            7.688652713279647,
+            [25.9, 9.1],
+            5,
+            &[
+                [0.730313187001, 0.256596525162],
+                [7.984250549601, 2.80527722013],
+                [15.2381879122, 5.353957915097],
+                [22.4921252748, 7.902638610065],
+                [29.7460626374, 10.451319305032],
+            ],
+        ),
+        // MEASURE-024: (list ename point).
+        (
+            (
+                "pline",
+                json!({"vertices": [{"p": [0.0, 0.0], "bulge": 0.0}, {"p": [100.0, 0.0], "bulge": 0.0}, {"p": [100.0, 10.0], "bulge": 0.0}, {"p": [5.0, 10.0], "bulge": 0.0}], "closed": false}),
+            ),
+            "measure",
+            7.0,
+            [90.0, 0.0],
+            29,
+            &[[7.0, 0.0], [7.0, 10.0], [14.0, 0.0], [98.0, 0.0], [98.0, 10.0], [100.0, 5.0]],
+        ),
+        // MEASURE-026: (list ename point).
+        (
+            (
+                "pline",
+                json!({"vertices": [{"p": [0.0, 0.0], "bulge": 0.0}, {"p": [10.0, 0.0], "bulge": 0.0}, {"p": [10.0, 100.0], "bulge": 0.0}], "closed": false}),
+            ),
+            "measure",
+            7.0,
+            [10.0, 30.0],
+            15,
+            &[[5.0, 0.0], [10.0, 2.0], [10.0, 9.0], [10.0, 79.0], [10.0, 86.0], [10.0, 93.0]],
+        ),
+        // MEASURE-030: (list ename point).
+        (
+            (
+                "pline",
+                json!({"vertices": [{"p": [0.0, 0.0], "bulge": 0.0}, {"p": [30.0, 0.0], "bulge": 0.5}, {"p": [45.0, 20.0], "bulge": 0.0}, {"p": [10.0, 35.0], "bulge": 0.0}], "closed": true}),
+            ),
+            "measure",
+            7.5,
+            [5.0, 17.5],
+            17,
+            &[
+                [2.06040845923, 7.211429607306],
+                [4.120816918461, 14.422859214612],
+                [5.957390538273, 0.0],
+                [41.854257779673, 5.445746712402],
+                [45.137412221497, 19.497902817843],
+                [45.215233654661, 12.07010340037],
+            ],
+        ),
+        // DIVIDE-028: (list ename point).
+        (
+            (
+                "pline",
+                json!({"vertices": [{"p": [0.0, 0.0], "bulge": 0.0}, {"p": [30.0, 0.0], "bulge": 0.5}, {"p": [45.0, 20.0], "bulge": 0.0}, {"p": [10.0, 35.0], "bulge": 0.0}], "closed": true}),
+            ),
+            "divide",
+            5.0,
+            [37.5, 10.0],
+            5,
+            &[
+                [0.0, 0.0],
+                [7.332712970983, 25.664495398441],
+                [25.609294779385, 28.310302237406],
+                [26.691478107655, 0.0],
+                [45.58190593662, 14.465330916891],
+            ],
+        ),
+        // MEASURE-041: (list ename point).
+        (
+            (
+                "pline",
+                json!({"vertices": [{"p": [0.0, 0.0], "bulge": 0.0}, {"p": [30.0, 0.0], "bulge": 0.5}, {"p": [45.0, 20.0], "bulge": 0.0}, {"p": [10.0, 35.0], "bulge": 0.0}], "closed": true}),
+            ),
+            "measure",
+            7.5,
+            [45.54951565955276, 17.15901034980981],
+            17,
+            &[
+                [1.636621047999, 5.728173667998],
+                [3.69702950723, 12.939603275304],
+                [5.75743796646, 20.15103288261],
+                [42.799868254703, 6.663750217618],
+                [44.060611317761, 20.402595149531],
+                [45.491536690495, 13.587129550966],
+            ],
+        ),
+        // MEASURE-042: (list ename point).
+        (
+            (
+                "pline",
+                json!({"vertices": [{"p": [0.0, 0.0], "bulge": 0.0}, {"p": [30.0, 0.0], "bulge": 0.5}, {"p": [45.0, 20.0], "bulge": 0.0}, {"p": [10.0, 35.0], "bulge": 0.0}], "closed": true}),
+            ),
+            "measure",
+            7.5,
+            [44.0, 20.5],
+            17,
+            &[
+                [2.06040845923, 7.211429607306],
+                [4.120816918461, 14.422859214612],
+                [5.957390538273, 0.0],
+                [41.854257779673, 5.445746712402],
+                [45.137412221497, 19.497902817843],
+                [45.215233654661, 12.07010340037],
+            ],
+        ),
+    ];
+    for ((seed, params), what, value, pick, count, want) in cases {
+        let mut s = Session::new();
+        let r = s.execute(seed, &params).unwrap();
+        let handle = r.get("handle").or_else(|| r["handles"].get(0)).and_then(serde_json::Value::as_str).unwrap().to_string();
+        // AutoLISP's (list ename point): the object and where it was picked.
+        let params = if what == "divide" {
+            json!({"handle": handle, "segments": value as u64, "from": pick})
+        } else {
+            json!({"handle": handle, "length": value, "from": pick})
+        };
+        s.execute(what, &params).unwrap();
+        let pts: Vec<Vec2> =
+            s.doc().unwrap().model.iter().filter_map(|e| if let EntityKind::Point(p) = &e.kind { Some(p.p.xy()) } else { None }).collect();
+        assert_eq!(pts.len(), count, "{what} {pick:?}: {pts:?}");
+        for w in want {
+            let tol = 1e-9 * w[0].abs().max(w[1].abs()).max(1.0);
+            assert!(pts.iter().any(|p| p.near(Vec2::new(w[0], w[1]), tol)), "{what} {pick:?}: no point at {w:?} in {pts:?}");
+        }
+    }
+}
+
+/// A spline's end is chosen by its own parameter: this one spends half its parameter range on a
+/// zero-length first span, so a pick at x = 3 is already past its middle (parameter 1.3 of 0..2) and
+/// MEASURE runs from the end, though x = 3 is short of the middle of the drawn length.
+#[test]
+fn measure_spline_by_its_own_parameter() {
+    let mut s = Session::new();
+    let sp = h(&s.execute("spline", &json!({"control": [[0, 0], [0, 0], [10, 0]], "degree": 1})).unwrap());
+    s.execute("measure", &json!({"handle": sp, "length": 3, "from": [3, 0]})).unwrap();
+    let pts: Vec<Vec2> =
+        s.doc().unwrap().model.iter().filter_map(|e| if let EntityKind::Point(p) = &e.kind { Some(p.p.xy()) } else { None }).collect();
+    assert!(pts.len() == 3 && [7.0, 4.0, 1.0].iter().all(|x| pts.iter().any(|p| near(*p, *x, 0.0))), "{pts:?}");
+}
+
 #[test]
 fn divide_and_measure_command_line() {
     let mut s = Session::new();
