fix long running transform bug (does not affect scaling)

The transforms need to be built in reverse. Intuition here is that you
have a point in its own coordinate system, and it must go through a series
of transforms to get to the overall SVG's coordinate system. That goes
from its last transform to the first transform of the svg.
master
Sameer Puri 4 years ago
parent e6fa930efc
commit 0d6711cc01

24
Cargo.lock generated

@ -2,9 +2,9 @@
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.15"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
@ -203,9 +203,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.3.4"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "num"
@ -368,9 +368,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.4.6"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
@ -379,9 +379,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.23"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "roxmltree"
@ -458,9 +458,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.70"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
@ -505,9 +505,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "uom"

@ -6,16 +6,10 @@
Convert any SVG 1.1 path to gcode for a pen plotter, laser engraver, etc.
## TODO
- [x] Support all path variants
- [x] Support group and path transforms
- [ ] Biarc interpolation (G2/G3 instead of many G1)
- [x] Px, pc, in to mm
- [x] Configurable DPI for px/pc to mm
- [ ] Sort paths by distance to reduce G0 distances
- [x] Configurable start/end sequence
- [ ] Comments in GCode input
- [ ] Rustdocs
- [ ] End-to-end tests
## Known bugs/issues
- [ ] Ellipse paths are dubious -- large_arc, sweep may need to be inverted

@ -96,13 +96,15 @@ pub fn svg2program<'input>(
if let Some(transform) = node.attribute("transform") {
let parser = TransformListParser::from(transform);
transforms.append(
&mut parser
transforms.extend(
parser
.map(|token| {
token.expect("could not parse a transform in a list of transforms")
})
.map(svg_transform_into_euclid_transform)
.collect(),
.collect::<Vec<_>>()
.iter()
.rev(),
)
}
@ -180,6 +182,8 @@ fn width_and_height_into_transform(
let width_in_mm = length_to_mm(width, options.dpi);
let height_in_mm = length_to_mm(height, options.dpi);
// SVGs have 0,0 in upper left
// g-code has 0,0 in lower left
Some(
Transform2D::scale(width_in_mm, -height_in_mm)
.then_translate(vector(0f64, height_in_mm)),

@ -431,7 +431,7 @@ impl<'input> Turtle<'input> {
/// https://www.w3.org/TR/SVG/coords.html#InterfaceSVGTransform
pub fn push_transform(&mut self, trans: Transform2D<f64>) {
self.transform_stack.push(self.current_transform);
self.current_transform = self.current_transform.then(&trans);
self.current_transform = trans.then(&self.current_transform);
}
/// Pop a generic transform off the stack, returning to the previous transform state

@ -1,11 +1,120 @@
G21
G94
G90
G0 X0 Y0;svg#svg8 > g#layer1 > path#path838
G0 X1 Y9
G1 X9 Y9 F300
G1 X9 Y1 F300
G1 X1 Y1 F300
G1 X1 Y9 F300
G1 X1 Y9 F300;svg#svg8 > g#layer1 > path#path832
G0 X8 Y2.5
G1 X7.992016 Y2.5889958186882955 F300
G1 X7.968318977024 Y2.675149466910962 F300
G1 X7.929665719197762 Y2.75570954175836 F300
G1 X7.877290656963224 Y2.828103276680163 F300
G1 X7.812866440307907 Y2.8900187053579076 F300
G1 X7.738450521014919 Y2.939478496661343 F300
G1 X7.656419445882797 Y2.974903102695401 F300
G1 X7.569392959326962 Y2.9951612032417794 F300
G1 X7.480150339222062 Y2.999605835601428 F300
G1 X7.391541637883766 Y2.9880950559953092 F300
G1 X7.306396662798014 Y2.9609964726809244 F300
G1 X7.227434603889145 Y2.9191755060150015 F300
G1 X7.1571771934704715 Y2.8639677503889835 F300
G1 X7.097868172201125 Y2.7971363206865427 F300
G1 X7.051401632984364 Y2.7208155454466567 F300
G1 X7.019261531216614 Y2.637442804947386 F300
G1 X7.00247429318793 Y2.549680691029316 F300
G1 X7.001576036131997 Y2.460331974562534 F300
G1 X7.016595446786152 Y2.372250096156122 F300
G1 X7.047052865251745 Y2.288248038678869 F300
G1 X7.091975603412658 Y2.211008491838367 F300
G1 X7.149929008702984 Y2.142998177802515 F300
G1 X7.2190622811713725 Y2.086389073960362 F300
G1 X7.297167580628271 Y2.042989048652211 F300
G1 X7.381750536230225 Y2.0141841250863033 F300
G1 X7.4701099067071315 Y2.000894217301639 F300
G1 X7.5 Y2 F300
G1 X7.5889958186882955 Y2.007984 F300
G1 X7.675149466910962 Y2.031681022976 F300
G1 X7.7557095417583595 Y2.0703342808022382 F300
G1 X7.828103276680163 Y2.1227093430367767 F300
G1 X7.890018705357908 Y2.1871335596920924 F300
G1 X7.9394784966613425 Y2.2615494789850814 F300
G1 X7.974903102695401 Y2.343580554117203 F300
G1 X7.995161203241779 Y2.4306070406730376 F300
G1 X7.999605835601428 Y2.519849660777938 F300
G1 X7.988095055995309 Y2.608458362116234 F300
G1 X7.960996472680924 Y2.6936033372019863 F300
G1 X7.9191755060150015 Y2.7725653961108554 F300
G1 X7.8639677503889835 Y2.842822806529529 F300
G1 X7.797136320686543 Y2.902131827798875 F300
G1 X7.720815545446657 Y2.948598367015636 F300
G1 X7.637442804947386 Y2.980738468783386 F300
G1 X7.549680691029316 Y2.9975257068120698 F300
G1 X7.460331974562534 Y2.998423963868003 F300
G1 X7.372250096156122 Y2.9834045532138482 F300
G1 X7.288248038678869 Y2.952947134748255 F300
G1 X7.211008491838367 Y2.9080243965873427 F300
G1 X7.142998177802515 Y2.850070991297016 F300
G1 X7.086389073960362 Y2.7809377188286284 F300
G1 X7.0429890486522115 Y2.7028324193717292 F300
G1 X7.014184125086303 Y2.6182494637697746 F300
G1 X7.000894217301639 Y2.5298900932928685 F300
G1 X7 Y2.5 F300
G1 X7.007984 Y2.4110041813117045 F300
G1 X7.0316810229760005 Y2.324850533089038 F300
G1 X7.070334280802238 Y2.24429045824164 F300
G1 X7.122709343036777 Y2.171896723319837 F300
G1 X7.187133559692093 Y2.109981294642092 F300
G1 X7.261549478985081 Y2.0605215033386575 F300
G1 X7.343580554117203 Y2.025096897304599 F300
G1 X7.430607040673038 Y2.004838796758221 F300
G1 X7.519849660777937 Y2.000394164398572 F300
G1 X7.608458362116234 Y2.0119049440046908 F300
G1 X7.693603337201985 Y2.0390035273190756 F300
G1 X7.7725653961108545 Y2.080824493984998 F300
G1 X7.842822806529528 Y2.136032249611016 F300
G1 X7.902131827798875 Y2.2028636793134564 F300
G1 X7.948598367015635 Y2.279184454553342 F300
G1 X7.980738468783386 Y2.362557195052612 F300
G1 X7.99752570681207 Y2.4503193089706823 F300
G1 X7.998423963868003 Y2.5396680254374644 F300
G1 X7.983404553213848 Y2.627749903843876 F300
G1 X7.952947134748256 Y2.711751961321129 F300
G1 X7.908024396587344 Y2.7889915081616308 F300
G1 X7.850070991297018 Y2.857001822197483 F300
G1 X7.78093771882863 Y2.9136109260396363 F300
G1 X7.702832419371732 Y2.9570109513477876 F300
G1 X7.618249463769778 Y2.9858158749136963 F300
G1 X7.529890093292872 Y2.999105782698361 F300
G1 X7.5000000000000036 Y3 F300
G1 X7.411004181311708 Y2.9920160000000005 F300
G1 X7.324850533089041 Y2.9683189770240013 F300
G1 X7.244290458241643 Y2.9296657191977635 F300
G1 X7.17189672331984 Y2.8772906569632255 F300
G1 X7.109981294642094 Y2.81286644030791 F300
G1 X7.060521503338659 Y2.7384505210149213 F300
G1 X7.0250968973046 Y2.6564194458828 F300
G1 X7.0048387967582215 Y2.5693929593269655 F300
G1 X7.000394164398572 Y2.480150339222065 F300
G1 X7.011904944004691 Y2.391541637883769 F300
G1 X7.039003527319075 Y2.306396662798017 F300
G1 X7.080824493984997 Y2.227434603889147 F300
G1 X7.136032249611015 Y2.1571771934704733 F300
G1 X7.202863679313455 Y2.0978681722011268 F300
G1 X7.279184454553341 Y2.051401632984365 F300
G1 X7.36255719505261 Y2.019261531216615 F300
G1 X7.4503193089706805 Y2.0024742931879307 F300
G1 X7.539668025437463 Y2.0015760361319965 F300
G1 X7.627749903843874 Y2.016595446786151 F300
G1 X7.711751961321127 Y2.047052865251743 F300
G1 X7.788991508161629 Y2.091975603412655 F300
G1 X7.857001822197482 Y2.1499290087029808 F300
G1 X7.9136109260396355 Y2.219062281171368 F300
G1 X7.957010951347787 Y2.2971675806282663 F300
G1 X7.985815874913696 Y2.3817505362302205 F300
G1 X7.9991057826983605 Y2.470109906707126 F300
G1 X8 Y2.4999999999999987 F300
G1 X8 Y2.5 F300
G0 X0 Y0
M2

@ -7,8 +7,8 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="square.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="square_transformed.svg"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
id="svg8"
version="1.1"
viewBox="0 0 10 10"
@ -20,16 +20,16 @@
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="2109"
inkscape:window-width="3836"
inkscape:window-height="768"
inkscape:window-width="1366"
units="mm"
showgrid="true"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="35.055997"
inkscape:cx="21.930942"
inkscape:zoom="22.4"
inkscape:cy="34.247607"
inkscape:cx="7.5651517"
inkscape:zoom="9.1957985"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
@ -51,7 +51,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -63,5 +63,9 @@
id="path838"
d="M 1,1 H 9 V 9 H 1 Z"
style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path832"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 8,7.5 A 0.5,0.5 0 0 1 7.5,8 0.5,0.5 0 0 1 7,7.5 0.5,0.5 0 0 1 7.5,7 0.5,0.5 0 0 1 8,7.5 Z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

@ -1,11 +1,120 @@
G21
G94
G90
G0 X0 Y19;svg#svg8 > g#layer1 > path#path838
G0 X9 Y8
G1 X9 Y0 F300
G1 X1 Y0 F300
G1 X0.9999999999999982 Y8 F300
G1 X9 Y8 F300
G0 X0 Y19
G0 X0 Y0;svg#svg8 > g#layer1 > path#path838
G0 X1 Y0.9999999999999999
G1 X1.0000000000000004 Y9 F300
G1 X9 Y9 F300
G1 X9 Y0.9999999999999994 F300
G1 X1 Y0.9999999999999999 F300;svg#svg8 > g#layer1 > path#path832
G0 X7.500000000000001 Y7.999999999999999
G1 X7.411004181311705 Y7.992016 F300
G1 X7.324850533089039 Y7.9683189770239995 F300
G1 X7.244290458241641 Y7.929665719197761 F300
G1 X7.171896723319838 Y7.877290656963223 F300
G1 X7.109981294642092 Y7.812866440307907 F300
G1 X7.0605215033386575 Y7.738450521014919 F300
G1 X7.025096897304599 Y7.656419445882797 F300
G1 X7.004838796758221 Y7.569392959326962 F300
G1 X7.000394164398572 Y7.480150339222062 F300
G1 X7.011904944004691 Y7.3915416378837655 F300
G1 X7.039003527319076 Y7.306396662798013 F300
G1 X7.0808244939849985 Y7.227434603889144 F300
G1 X7.1360322496110165 Y7.157177193470471 F300
G1 X7.202863679313457 Y7.0978681722011245 F300
G1 X7.279184454553342 Y7.051401632984363 F300
G1 X7.362557195052613 Y7.019261531216613 F300
G1 X7.450319308970683 Y7.002474293187929 F300
G1 X7.539668025437465 Y7.001576036131996 F300
G1 X7.627749903843877 Y7.016595446786151 F300
G1 X7.71175196132113 Y7.047052865251743 F300
G1 X7.788991508161631 Y7.0919756034126555 F300
G1 X7.857001822197484 Y7.149929008702982 F300
G1 X7.913610926039636 Y7.21906228117137 F300
G1 X7.957010951347788 Y7.297167580628268 F300
G1 X7.985815874913697 Y7.381750536230222 F300
G1 X7.999105782698361 Y7.470109906707128 F300
G1 X8 Y7.499999999999997 F300
G1 X7.9920160000000005 Y7.588995818688293 F300
G1 X7.968318977024 Y7.67514946691096 F300
G1 X7.929665719197763 Y7.755709541758358 F300
G1 X7.877290656963225 Y7.82810327668016 F300
G1 X7.812866440307909 Y7.890018705357906 F300
G1 X7.73845052101492 Y7.939478496661341 F300
G1 X7.656419445882799 Y7.9749031026954 F300
G1 X7.569392959326964 Y7.995161203241778 F300
G1 X7.480150339222064 Y7.999605835601427 F300
G1 X7.391541637883768 Y7.988095055995308 F300
G1 X7.306396662798016 Y7.9609964726809235 F300
G1 X7.2274346038891455 Y7.9191755060150015 F300
G1 X7.157177193470472 Y7.8639677503889835 F300
G1 X7.097868172201126 Y7.797136320686543 F300
G1 X7.051401632984365 Y7.720815545446658 F300
G1 X7.019261531216614 Y7.637442804947387 F300
G1 X7.00247429318793 Y7.549680691029317 F300
G1 X7.001576036131997 Y7.460331974562535 F300
G1 X7.016595446786152 Y7.372250096156122 F300
G1 X7.047052865251744 Y7.288248038678869 F300
G1 X7.091975603412656 Y7.211008491838367 F300
G1 X7.149929008702983 Y7.142998177802515 F300
G1 X7.219062281171371 Y7.086389073960362 F300
G1 X7.297167580628269 Y7.042989048652211 F300
G1 X7.381750536230223 Y7.014184125086302 F300
G1 X7.47010990670713 Y7.000894217301639 F300
G1 X7.5 Y6.999999999999999 F300
G1 X7.588995818688295 Y7.007983999999999 F300
G1 X7.675149466910961 Y7.031681022975999 F300
G1 X7.755709541758359 Y7.070334280802237 F300
G1 X7.828103276680162 Y7.122709343036775 F300
G1 X7.890018705357908 Y7.187133559692091 F300
G1 X7.9394784966613425 Y7.26154947898508 F300
G1 X7.974903102695401 Y7.343580554117201 F300
G1 X7.995161203241779 Y7.430607040673036 F300
G1 X7.999605835601428 Y7.519849660777936 F300
G1 X7.988095055995309 Y7.608458362116233 F300
G1 X7.960996472680924 Y7.693603337201984 F300
G1 X7.9191755060150015 Y7.772565396110854 F300
G1 X7.8639677503889835 Y7.842822806529528 F300
G1 X7.797136320686543 Y7.902131827798874 F300
G1 X7.720815545446658 Y7.948598367015635 F300
G1 X7.637442804947387 Y7.980738468783385 F300
G1 X7.549680691029317 Y7.997525706812069 F300
G1 X7.460331974562535 Y7.998423963868002 F300
G1 X7.372250096156123 Y7.983404553213847 F300
G1 X7.28824803867887 Y7.952947134748255 F300
G1 X7.211008491838368 Y7.908024396587342 F300
G1 X7.142998177802516 Y7.850070991297016 F300
G1 X7.086389073960363 Y7.780937718828628 F300
G1 X7.0429890486522115 Y7.702832419371729 F300
G1 X7.014184125086303 Y7.618249463769775 F300
G1 X7.000894217301639 Y7.5298900932928685 F300
G1 X7 Y7.5 F300
G1 X7.0079839999999995 Y7.411004181311705 F300
G1 X7.031681022976 Y7.324850533089039 F300
G1 X7.070334280802238 Y7.2442904582416405 F300
G1 X7.122709343036776 Y7.171896723319838 F300
G1 X7.187133559692092 Y7.109981294642092 F300
G1 X7.2615494789850805 Y7.0605215033386575 F300
G1 X7.343580554117202 Y7.025096897304599 F300
G1 X7.430607040673037 Y7.0048387967582215 F300
G1 X7.519849660777936 Y7.000394164398572 F300
G1 X7.608458362116233 Y7.011904944004691 F300
G1 X7.693603337201985 Y7.039003527319076 F300
G1 X7.7725653961108545 Y7.080824493984998 F300
G1 X7.842822806529528 Y7.136032249611016 F300
G1 X7.902131827798874 Y7.202863679313456 F300
G1 X7.948598367015635 Y7.2791844545533415 F300
G1 X7.980738468783385 Y7.362557195052611 F300
G1 X7.99752570681207 Y7.450319308970681 F300
G1 X7.998423963868003 Y7.5396680254374635 F300
G1 X7.983404553213849 Y7.627749903843875 F300
G1 X7.952947134748257 Y7.711751961321128 F300
G1 X7.9080243965873445 Y7.78899150816163 F300
G1 X7.850070991297018 Y7.857001822197482 F300
G1 X7.780937718828631 Y7.9136109260396355 F300
G1 X7.702832419371733 Y7.957010951347787 F300
G1 X7.618249463769779 Y7.985815874913696 F300
G1 X7.529890093292873 Y7.9991057826983605 F300
G1 X7.500000000000004 Y8 F300
G1 X7.500000000000001 Y7.999999999999999 F300
G0 X0 Y0
M2

@ -7,8 +7,8 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="square_translated.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="square_transformed.svg"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
id="svg8"
version="1.1"
viewBox="0 0 10 10"
@ -20,16 +20,16 @@
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="2109"
inkscape:window-width="3836"
inkscape:window-height="768"
inkscape:window-width="1366"
units="mm"
showgrid="true"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="35.055997"
inkscape:cx="21.930942"
inkscape:zoom="22.4"
inkscape:cy="34.247607"
inkscape:cx="7.5651517"
inkscape:zoom="9.1957985"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
@ -51,18 +51,22 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
inkscape:label="Layer 1"
transform="rotate(-90, 5, 5)">
<path
id="path838"
transform="rotate(-90, 5, 5)"
d="M 1,1 H 9 V 9 H 1 Z"
style="fill:none;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path832"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 8,7.5 A 0.5,0.5 0 0 1 7.5,8 0.5,0.5 0 0 1 7,7.5 0.5,0.5 0 0 1 7.5,7 0.5,0.5 0 0 1 8,7.5 Z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Loading…
Cancel
Save