my
%imap
= (
m
=> [
qw/x y/
],
z
=> [],
l
=> [
qw/x y/
],
h
=> [
'x'
],
v
=> [
'y'
],
c
=> [
qw/x1 y1 x2 y2 x y/
],
s
=> [
qw/x1 y1 x y/
],
q =>
[
qw/x1 y1 x y/
],
t
=> [
qw/x y/
],
a
=> [
qw/rx ry xr l s x y/
],
);
sub
new
{
my
(
$proto
,
%opts
) =
@_
;
return
$proto
->SUPER::new(
%opts
);
}
sub
serialise
{
my
(
$self
) =
@_
;
my
$lastmode
=
''
;
my
$result
=
''
;
foreach
my
$inst
(
$self
->instructions) {
my
%inst
= %{
$inst
};
$result
.=
' '
if
length
(
$result
);
my
$rel
=
$inst
{
'rel'
};
my
$mode
=
$inst
{
'mode'
};
my
@c
=
@inst
{@{
$imap
{
$mode
}}};
$mode
=
uc
(
$mode
)
if
not
$rel
;
$result
.=
$mode
.
' '
if
$mode
ne
$lastmode
;
$result
.=
join
(
' '
,
@c
)
if
@c
;
$lastmode
=
$mode
;
}
$result
=~ s/\s+$//;
return
$result
;
}
sub
deserialise
{
my
(
$self
,
$path
) =
@_
;
$path
=~ s/(\+|-)/ $1/g;
$path
=~ s/([MmZzLlHhVvCcSsQqTtAa])/ $1 /g;
$path
=~ s/,/ /g;
$path
=~ s/^\s+//;
$path
=~ s/\s+$//;
my
@path
=
split
(/\s+/,
$path
);
my
@inst
;
my
$mode
;
for
(
my
$i
= 0;
$i
<=
$#path
;
$i
++) {
my
$s
=
$path
[
$i
];
next
if
not
defined
(
$s
);
if
(
defined
(
$imap
{
lc
(
$s
)})) {
$mode
=
$s
;
if
(not @{
$imap
{
lc
(
$mode
)}}) {
push
@inst
, _instruction(
$mode
);
}
else
{
next
;
}
}
elsif
(
$s
=~ /^\-*\d+\.*\d*$/) {
my
$length
= @{
$imap
{
lc
(
$mode
)}};
my
$end
=
$i
+
$length
;
next
if
not
$end
;
push
@inst
, _instruction(
$mode
,
@path
[
$i
..
$end
]);
$mode
=
'l'
if
(
$mode
eq
'm'
);
$mode
=
'L'
if
(
$mode
eq
'M'
);
$i
+=
$length
- 1;
}
else
{
die
"Error in path, unexpected instruction '$s' - "
.
join
(
', '
,
keys
(
%imap
)).
"\n"
;
}
}
$self
->{
'path'
} = \
@inst
;
return
$self
;
}
sub
_instruction
{
my
(
$mode
,
@c
) =
@_
;
my
$reletive
= (
$mode
=~ /A-Z/) ? 1 : 0;
$mode
=
lc
(
$mode
);
my
%inst
= (
mode
=>
$mode
,
rel
=>
$reletive
);
@inst
{@{
$imap
{
$mode
}}} =
@c
if
@c
;
return
\
%inst
;
}
sub
instructions
{
my
(
$self
) =
@_
;
return
@{
$self
->{
'path'
}};
}
return
1;