Commit 4b5ffbf
Fix the sulcus SVG export, which pycortex could not read
A code review checked sulci.svg against cortex/svgoverlay.py for the first time.
The v0.4.0 export was broken three ways, none of which its ten unit tests could
see, because they all matched the output string rather than parsing it.
1. Not well-formed XML: the inkscape: prefix with no namespace declaration and
no <svg> root. ET.parse -> ParseError: unbound prefix.
2. The <text data-ptidx> labels crashed db.get_overlay(). Labels.__init__ does
an unguarded float(text.get('x')) over every <text> in a labels layer; ours
had no x/y, because a vertex index cannot supply one.
3. data-ptidx is pycortex's output, not its input. SVGOverlay.set_coords
computes it by kd-tree from each label's x/y. A real overlays.svg has zero
<text> elements: Shape.get_labelpos() derives one label per path, so a
two-hemisphere sulcus is labelled twice for free.
So: emit a standalone SVG (both namespaces declared, viewBox from the overlay),
and no labels at all -- but keep the labels layer, empty, since _find_layer
raises ValueError without it. The file now carries an XML comment warning that
its shape groups must be copied into the subject's existing #sulci_shapes: a
second inkscape:label="sulci" layer silently replaces the subject's own.
test/test_sulci_svg.py generates the writer's real output with node and parses
it with ElementTree, using svgoverlay.py's own namespaces and findall queries.
It needs neither cortex nor a subject, so it runs in CI. Every new assertion was
mutation-checked against the code it guards.
Also, from the same review:
- All five bezier edit ops now share one out-of-range contract (unchanged copy).
setAnchorSmooth and splitSegment threw TypeError, deleteAnchor silently no-op'd,
and setAnchorSmooth on a closed curve grew smooth[] past anchors[] with holes --
the exact desync inRange was added to prevent.
- loadJSON deep-copies, as its comment already claimed. It aliased r.bezier and
every outline {h,g}.
- _sync retries when setOverlayLayer reports the SVG overlay isn't loaded; a
shape used to sit listed and counted in the panel, never drawn.
- _editToggle refuses a bezier-less shape, which used to leave editingId naming a
shape the overlay wasn't editing.
- exportSulciMarkup separates "overlay not loaded" (null) from "no usable curve" ("").
- Timers and the adapter's setData listener are released by destroy().
- The live sulcus stroke and the exported one read one pair of constants.
- Export byte counts use TextEncoder, not String.length.
- The lasso rejects a degenerate stroke, as the trace already did.
- fitHomography requires dst to span 2D, not just src.
- roi -> shape in the edit overlay; several stale header comments corrected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1 parent d5fd762 commit 4b5ffbf
19 files changed
Lines changed: 859 additions & 290 deletions
File tree
- adapter
- core
- docs/superpowers
- test
- ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
15 | | - | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| |||
72 | 73 | | |
73 | 74 | | |
74 | 75 | | |
75 | | - | |
| 76 | + | |
| 77 | + | |
76 | 78 | | |
77 | 79 | | |
78 | 80 | | |
| |||
132 | 134 | | |
133 | 135 | | |
134 | 136 | | |
135 | | - | |
136 | | - | |
137 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
138 | 140 | | |
139 | 141 | | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
147 | 154 | | |
| 155 | + | |
148 | 156 | | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
| 157 | + | |
153 | 158 | | |
154 | 159 | | |
155 | | - | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
156 | 173 | | |
157 | 174 | | |
158 | 175 | | |
159 | 176 | | |
160 | 177 | | |
161 | 178 | | |
162 | 179 | | |
163 | | - | |
164 | | - | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
165 | 192 | | |
166 | 193 | | |
167 | 194 | | |
| |||
179 | 206 | | |
180 | 207 | | |
181 | 208 | | |
182 | | - | |
| 209 | + | |
183 | 210 | | |
184 | 211 | | |
185 | 212 | | |
| |||
191 | 218 | | |
192 | 219 | | |
193 | 220 | | |
194 | | - | |
| 221 | + | |
| 222 | + | |
195 | 223 | | |
196 | 224 | | |
197 | 225 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
36 | 48 | | |
37 | 49 | | |
38 | 50 | | |
| |||
57 | 69 | | |
58 | 70 | | |
59 | 71 | | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
67 | 87 | | |
68 | 88 | | |
69 | 89 | | |
| |||
109 | 129 | | |
110 | 130 | | |
111 | 131 | | |
112 | | - | |
113 | | - | |
114 | | - | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
115 | 135 | | |
116 | 136 | | |
117 | | - | |
| 137 | + | |
118 | 138 | | |
119 | 139 | | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
134 | 164 | | |
135 | 165 | | |
136 | 166 | | |
| |||
0 commit comments