Perl+OpenGL 重绘inkscape生成的svg矢量图

There's more than one way to do it!
https://metacpan.org http://perlmonks.org
回复
头像
523066680
Administrator
Administrator
帖子: 573
注册时间: 2016年07月19日 12:14
联系:

Perl+OpenGL 重绘inkscape生成的svg矢量图

帖子 523066680 »

还不够完善,先挖个坑,后面慢慢填
=info
Author: 523066680
Date: 2016-11
=cut

use IO::Handle;
use OpenGL qw/ :all /;
use OpenGL::Config;
use Time::HiRes 'sleep';
use feature 'state';

STDOUT->autoflush(1);

open READ, "<:raw", "multi.svg";
my @all;
my $tl;
for my $line (<READ>)
{
if ( $line=~/\s+d="(.*)"/ )
{
@all = split(" ", $1 );
}
}

my @coords;

for my $e (@all)
{
if ( $e =~/[a-zA-Z]/ )
{
$head = $e;
next;
}
push @coords,
{
'head' => $head,
'data' => [ split(",", $e) ],
};
}

#相对坐标 叠加为绝对坐标
my ($ox, $oy);
for (my $i = 0; $i <= $#coords; $i++)
{
if ($coords[$i]->{head} eq 'c')
{
grep
{
$coords[ $i+$_ ]->{'data'}[0] += $ox;
$coords[ $i+$_ ]->{'data'}[1] += $oy;
} (0..2) ;
$i += 2;
}
else
{

}
#ox oy 始终是最后一点的坐标值
($ox, $oy) = ($coords[$i]->{'data'}[0], $coords[$i]->{'data'}[1]) ;
}

my ($xmin, $xmax, $ymin, $ymax) = (10000.0, -10000.0, 10000.0, -10000.0);
for my $e (@coords)
{
printf("%.2f, %.2f\n", $e->{'data'}[0], $e->{'data'}[1]);
$xmin = $e->{'data'}[0] if ($e->{'data'}[0] < $xmin);
$xmax = $e->{'data'}[0] if ($e->{'data'}[0] > $xmax);

$ymin = $e->{'data'}[1] if ($e->{'data'}[1] < $ymin);
$ymax = $e->{'data'}[1] if ($e->{'data'}[1] > $ymax);
}
printf("%f %f %f %f\n", $xmin, $xmax, $ymin, $ymax);

&Main();

sub display
{
glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

glPushMatrix();

my $array;
my @points;

for (my $i = 0; $i <= $#coords; $i++)
{
if ($coords[$i]->{head} eq 'C')
{
glColor4f(0.0,0.5,0.0,1.0);
$array = OpenGL::Array->new( 3*4, GL_FLOAT);
@points = (
$coords[$i-1]->{'data'}[0], $coords[$i-1]->{'data'}[1], 0.0 ,
$coords[$i+0]->{'data'}[0], $coords[$i+0]->{'data'}[1], 0.0 ,
$coords[$i+1]->{'data'}[0], $coords[$i+1]->{'data'}[1], 0.0 ,
$coords[$i+2]->{'data'}[0], $coords[$i+2]->{'data'}[1], 0.0 ,
);

$array->assign(0, @points);

glMap1f_c(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, $array->ptr);
glMapGrid1f(20, 0.0, 1.0);
glEvalMesh1(GL_LINE, 0, 20);
$i+=2;
}
elsif ($coords[$i]->{head} eq 'c')
{
glColor4f(0.0,0.5,0.0,1.0);
$array = OpenGL::Array->new( 3*4, GL_FLOAT);

@points = ( $coords[$i-1]->{'data'}[0], $coords[$i-1]->{'data'}[1], 0.0,
$coords[$i+0]->{'data'}[0], $coords[$i+0]->{'data'}[1], 0.0 ,
$coords[$i+1]->{'data'}[0], $coords[$i+1]->{'data'}[1], 0.0 ,
$coords[$i+2]->{'data'}[0], $coords[$i+2]->{'data'}[1], 0.0 ,
);

$array->assign(0, @points);

glMap1f_c(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, $array->ptr);
glMapGrid1f(20, 0.0, 1.0);
glEvalMesh1(GL_LINE, 0, 20);
$i += 2;
}
elsif ($coords[$i]->{head} eq 'L')
{
glBegin(GL_LINES);
glVertex3f( $coords[$i-1]->{'data'}[0], $coords[$i-1]->{'data'}[1], 0.0 );
glVertex3f( $coords[$i]->{'data'}[0], $coords[$i]->{'data'}[1], 0.0 );
glEnd();
}
elsif ($coords[$i]->{head} =~/m/i)
{
glBegin(GL_POINTS);
glColor3f(1.0, 1.0, 1.0);
glVertex3f( $coords[$i]->{'data'}[0], $coords[$i]->{'data'}[1], 0.0 );
glEnd();
}
}

glPopMatrix();
glutSwapBuffers();
}

sub init
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glPointSize(2.0);
glLineWidth(2.0);
glEnable(GL_BLEND);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_MAP1_VERTEX_3);
}

sub idle
{
sleep 0.05;
glutPostRedisplay();
}

sub Reshape
{
my $half = 1000;
glViewport(0, 0, 500.0, 500.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
#glOrtho(-$half, $half, -$half, $half, 0.0, 200.0);
glOrtho($xmin, $xmax, $ymin, $ymax, 0.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,100.0,0.0,0.0,0.0, 0.0,1.0,100.0);
}

sub hitkey
{
my $keychar = lc(chr(shift));
if ($keychar eq 'q')
{
glutDestroyWindow($WinID);
}
}

sub Main
{
glutInit();
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize(500, 500);
glutInitWindowPosition(1,1);
our $WinID = glutCreateWindow("title");
&init();
glutDisplayFunc(\&display);
glutReshapeFunc(\&Reshape);
glutKeyboardFunc(\&hitkey);
glutIdleFunc(\&idle);
glutMainLoop();
}


__END__
要使glMap1f_c 正常工作,需要借用OpenGL::Array 建立一个
仿C的指针

my $array = OpenGL::Array->new( 3*4, GL_FLOAT);
$array->assign(0, @points);

glMap1f_c(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, $array->ptr);
glEnable(GL_MAP1_VERTEX_3);
请将一下内容保存到multi.svg,保存后可以拖入IE或者火狐中浏览。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
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"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="penta.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="402.20655"
inkscape:cy="647.84062"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1440"
inkscape:window-height="837"
inkscape:window-x="-4"
inkscape:window-y="120"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="fill-rule:evenodd"
id="path4140"
sodipodi:sides="11"
sodipodi:cx="421.86606"
sodipodi:cy="388.68654"
sodipodi:r1="219.29707"
sodipodi:r2="63.376858"
sodipodi:arg1="0.029801473"
sodipodi:arg2="-2.8262334"
inkscape:flatsided="false"
inkscape:rounded="-0.07"
inkscape:randomized="0"
d="m 641.06576,395.22096 c -0.58462,19.63861 -285.54568,-7.5131 -279.45113,-26.19125 6.09452,-18.67807 252.23038,127.45733 241.12118,143.66224 C 591.62657,528.89693 366.58139,351.99388 381.80662,339.57579 397.03179,327.15774 525.08769,583.16575 506.981,590.7921 488.87423,598.41849 395.1952,327.92957 414.7172,325.71418 c 19.52193,-2.21538 -11.15897,282.38451 -30.51441,279.01099 -19.35551,-3.37353 48.07402,-281.57 65.6947,-272.87931 17.62062,8.69065 -162.05612,231.52397 -176.51508,218.22165 -14.45903,-13.30238 192.67067,-210.88099 202.79559,-194.04345 10.12488,16.83746 -261.50159,107.1562 -266.47347,88.14847 -4.9719,-19.00782 276.09575,-73.23875 275.51032,-53.60016 -0.58543,19.6385 -277.92215,-51.2329 -271.82841,-69.91123 6.09378,-18.6784 271.86238,87.65628 260.75247,103.8608 -11.10987,16.20446 -206.1044,-193.35592 -190.87975,-205.77459 15.22471,-12.41873 181.31462,220.72105 163.20754,228.34669 -18.107,7.6256 -68.84995,-274.0898 -49.32811,-276.30599 19.52191,-2.2162 33.20075,283.70845 13.84538,280.33412 -19.3553,-3.37432 90.26387,-267.80211 107.88484,-259.11218 17.62105,8.68996 -125.45412,256.62042 -139.91259,243.31744 -14.45842,-13.30292 220.71955,-176.48913 230.84513,-159.65209 10.12562,16.83712 -244.2782,148.05723 -249.24931,129.04921 -4.97109,-19.00794 281.09833,-29.14211 280.51372,-9.50359 z" />
</g>
</svg>
IE浏览和脚本绘制截图:
drawsvg01.png
头像
523066680
Administrator
Administrator
帖子: 573
注册时间: 2016年07月19日 12:14
联系:

进一步地,绘制多个path元素

帖子 523066680 »

图片
=info
Author: 523066680
Date: 2016-11

V2.1 完善 q l m 的坐标叠加
v2.3 支持多个路径元素,但仍出现(文件夹图标)多余连线,原因:某些z标记被忽略
v2.4 解决2.3问题,窗口范围自适应
=cut

use IO::Handle;
use OpenGL qw/ :all /;
use OpenGL::Config;
use Time::HiRes 'sleep';
use feature 'state';
STDOUT->autoflush(1);

our $width = 500;
our $height = 500;

open READ, "<:raw", "fonts3.svg" or die "$!";
my @all;
my $tl;
for my $line (<READ>)
{
if ( $line=~s/\s+d="(.*)"// )
{
push @all, split(" ", $1);
push @all, ("w", "0,0") ; #自定义边界 w
}
}

my @coords;

for my $e (@all)
{
if ( $e =~/[a-zA-Z]/ )
{
$head = $e;

#如果遇到单独z的边界,手动添加最后一次获取的坐标
if ($head =~/z/i)
{
push @coords,
{
'head' => $head,
'data' => $coords[-1]->{'data'},
};
}
next;
}
push @coords,
{
'head' => $head,
'data' => [ split(",", $e) ],
};
}

#相对坐标 叠加为绝对坐标
my ($ox, $oy);
for (my $i = 0; $i <= $#coords; $i++)
{
if ($coords[$i]->{head} eq 'c')
{
grep
{
$coords[ $i+$_ ]->{'data'}[0] += $ox;
$coords[ $i+$_ ]->{'data'}[1] += $oy;
} (0..2) ;
$i += 2;
}
elsif ($coords[$i]->{head} eq 'q')
{
grep
{
$coords[ $i+$_ ]->{'data'}[0] += $ox;
$coords[ $i+$_ ]->{'data'}[1] += $oy;
} (0, 1) ;
$i += 1;
}
elsif ($coords[$i]->{head} eq 'l')
{
$coords[$i]->{'data'}[0] += $ox;
$coords[$i]->{'data'}[1] += $oy;
}
elsif ($coords[$i]->{head} eq 'm' and $i > 0)
{
$coords[$i]->{'data'}[0] += $ox ;
$coords[$i]->{'data'}[1] += $oy ;
}
elsif ($coords[$i]->{head} eq 'w')
{
$coords[$i]->{'data'}[0] = 0 ;
$coords[$i]->{'data'}[1] = 0 ;
}

#ox oy 始终是最后一点的坐标值
($ox, $oy) = ($coords[$i]->{'data'}[0], $coords[$i]->{'data'}[1]) ;
}

my ($xmin, $xmax, $ymin, $ymax) = (10000.0, -10000.0, 10000.0, -10000.0);
for my $e (@coords)
{
next if ( $e->{head} eq 'w' ); #自定义标签不参与计算

printf("%s : %.2f, %.2f\n", $e->{'head'}, $e->{'data'}[0], $e->{'data'}[1]);
$xmin = $e->{'data'}[0] if ($e->{'data'}[0] < $xmin);
$xmax = $e->{'data'}[0] if ($e->{'data'}[0] > $xmax);

$ymin = $e->{'data'}[1] if ($e->{'data'}[1] < $ymin);
$ymax = $e->{'data'}[1] if ($e->{'data'}[1] > $ymax);
}
printf("xmin: %.2f, xmax: %.2f, ymin: %.2f, ymax: %.2f\n", $xmin, $xmax, $ymin, $ymax);

&Main();

sub drawPoint
{
glBegin(GL_POINTS);
glVertex3f( shift, shift, 1.0 );
glEnd();
}

sub drawLine
{
glBegin(GL_LINES);
glVertex3f( shift, shift, 1.0 );
glVertex3f( shift, shift, 1.0 );
glEnd();
}


sub drawCurve
{
my $n = shift;
my $array;
$array = OpenGL::Array->new( 3 * $n , GL_FLOAT);
$array->assign(0, @_);

glMap1f_c(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, $n, $array->ptr);
glMapGrid1f(20, 0.0, 1.0);
glEvalMesh1(GL_LINE, 0, 20);
}

sub display
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();
my $edge = 0;

for (my $i = 0; $i <= $#coords; $i++)
{
$coords[$i]->{'data'}[0] += rand() * 2.0 - 1.0 ;
$coords[$i]->{'data'}[1] += rand() * 2.0 - 1.0 ;
if ($coords[$i]->{head} =~/C/i)
{
glColor4f(1.0,0.5,0.0,1.0);
drawCurve( 4,
@{$coords[$i-1]->{'data'}}, 0.0,
@{$coords[$i+0]->{'data'}}, 0.0,
@{$coords[$i+1]->{'data'}}, 0.0,
@{$coords[$i+2]->{'data'}}, 0.0
);
$i+=2;
drawPoint( @{$coords[$i]->{'data'}} );
}
elsif ($coords[$i]->{head} =~/Q/i)
{
glColor4f(0.3, 0.7, 0.8, 1.0);
drawCurve( 3,
@{$coords[$i-1]->{'data'}}, 0.0,
@{$coords[$i+0]->{'data'}}, 0.0,
@{$coords[$i+1]->{'data'}}, 0.0,
);
$i += 1;
drawPoint( @{$coords[$i]->{'data'}} );
}
elsif ($coords[$i]->{head} =~/L/i)
{
glColor3f(0.9, 0.6, 0.3);
drawLine( @{$coords[$i-1]->{'data'}}, @{$coords[$i]->{'data'}} );
}
elsif ($coords[$i]->{head} =~/M/i)
{
if ( $i > 0 and $coords[$i-1]->{head} =~/M/i ) #如果上一次也是m
{
glColor3f(0.8, 0.3, 0.3);
drawLine( @{$coords[$i-1]->{'data'}}, @{$coords[$i]->{'data'}} );

# glColor3f(0.0, 0.0, 0.0);
# drawPoint( @{$coords[$i]->{'data'}} );
}
else
{
glColor3f(0.0, 0.0, 0.0);
drawPoint( @{$coords[$i]->{'data'}} );
}
}
}

glPopMatrix();
glutSwapBuffers();
}

sub init
{
glClearColor(1.0, 1.0, 0.9, 1.0);
glPointSize(4.0);
glLineWidth(2.0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_MAP1_VERTEX_3);
}

sub idle
{
sleep 0.01;
glutPostRedisplay();
}

sub Reshape
{
our ($width, $height);
my $dtx = $xmax - $xmin;
my $dty = $ymax - $ymin;

if ( $dtx > $dty )
{
$dty *= $width / $dtx ;
$dtx = $width;
}
else
{
$dtx *= $height / $dty ;
$dty = $height;
}

glViewport(0, 0, $dtx, $dty );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho($xmin, $xmax, $ymax, $ymin, 0.0, 200.0); #y轴颠倒
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,100.0,0.0,0.0,0.0, 0.0,1.0,100.0);
}

sub hitkey
{
my $keychar = lc(chr(shift));
if ($keychar eq 'q')
{
glutDestroyWindow($WinID);
}
}

sub Main
{
glutInit();
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE |GLUT_DEPTH |GLUT_MULTISAMPLE );
glutInitWindowSize(500, 500);
glutInitWindowPosition(1,1);
our $WinID = glutCreateWindow("title");
&init();
glutDisplayFunc(\&display);
glutReshapeFunc(\&Reshape);
glutKeyboardFunc(\&hitkey);
glutIdleFunc(\&idle);
glutMainLoop();
}
fonts3.svg
(26.02 KiB) 已下载 4 次
回复

在线用户

正浏览此版面之用户: 没有注册用户 和 0 访客