245 lines
6.4 KiB
C++
245 lines
6.4 KiB
C++
#include<bits/stdc++.h>
|
|
|
|
#define N 100
|
|
|
|
using namespace std;
|
|
|
|
float XL=0.1;
|
|
float XR=0.1;
|
|
float YL=0.1;
|
|
float YR=0.1;
|
|
float vertex_R=.1;
|
|
float border_width=.01;
|
|
float output_scale = 100;
|
|
string border_color="#616161";
|
|
string label = "none";
|
|
string font_family = "Atkinson Hyperlegible";
|
|
string font_color = "white";
|
|
string Xdir="right";
|
|
string Ydir="down";
|
|
string output_file="g2s_output.svg";
|
|
string output_shape="default";
|
|
map<string,string> color_map,label_map;
|
|
|
|
const map<string,float*> float_config_item{
|
|
{"OutputScale",&output_scale}, //输出比例
|
|
{"XL",&XL}, //左边框留白比例
|
|
{"XR",&XR}, //右边框留白比例
|
|
{"YL",&YL}, //上边框留白比例
|
|
{"YR",&YR}, //下边框留白比例
|
|
{"R",&vertex_R}, //点的半径
|
|
{"Thickness",&border_width} //点的边框粗细
|
|
};
|
|
const map<string,string*> string_config_item{
|
|
{"BorderColor",&border_color}, //点的边框和边的颜色
|
|
{"Label",&label}, // 标签格式
|
|
{"FontFamily",&font_family}, // 标签字体
|
|
{"FontColor",&font_color}, // 标签颜色
|
|
{"Xaxis",&Xdir}, //x轴正方向
|
|
{"Yaxis",&Ydir}, //y轴正方向
|
|
{"OutputFile",&output_file}, //输出文件名
|
|
{"OutputShape",&output_shape} //输出形状
|
|
};
|
|
const map<string,vector<string>> string_config_item_options{
|
|
{"Label",{"a","A","1","none"}},
|
|
{"Xaxis",{"left","right"}},
|
|
{"Yaxis",{"up","down"}},
|
|
{"OutputShape",{"default","square"}}
|
|
};
|
|
//ColorMap: 颜色映射表
|
|
|
|
void getstring(string &s)
|
|
{
|
|
getchar();
|
|
s.clear();
|
|
char ch=getchar();
|
|
while(ch!='\"') s+=ch,ch=getchar();
|
|
}
|
|
|
|
void printlist(vector<string> vec)
|
|
{
|
|
fprintf(stderr,R"("%s")",vec[0].c_str());
|
|
for(size_t i=1;i+1<vec.size();i++)
|
|
fprintf(stderr,R"(, "%s")",vec[i].c_str());
|
|
if(vec.size()>1)
|
|
fprintf(stderr,R"( and "%s")",vec.back().c_str());
|
|
}
|
|
|
|
void init()
|
|
{
|
|
for(int line=1;;line++)
|
|
{
|
|
char ch=getchar();
|
|
while(ch!='-'&&!isalpha(ch)) ch=getchar();
|
|
if(ch=='-')
|
|
{
|
|
while(ch=='-') ch=getchar();
|
|
break;
|
|
}
|
|
string s;
|
|
while(isalpha(ch)) s+=ch,ch=getchar();
|
|
|
|
if(float_config_item.find(s)!=float_config_item.end()) cin>>*(float_config_item.at(s));
|
|
else if(string_config_item.find(s)!=string_config_item.end())
|
|
{
|
|
getstring(*(string_config_item.at(s)));
|
|
if(string_config_item_options.find(s)!=string_config_item_options.end())
|
|
{
|
|
bool bel=0;
|
|
auto vec=string_config_item_options.at(s);
|
|
string ss=s;
|
|
s=*string_config_item.at(s);
|
|
for(string t:vec) bel|=(s==t);
|
|
if(!bel)
|
|
{
|
|
fprintf(stderr,R"(Error on line %d: "%s" is not a valid option of "%s"
|
|
Valid options: )",line,s.c_str(),ss.c_str());
|
|
printlist(vec);
|
|
fprintf(stderr,".\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
else if(s=="ColorMap")
|
|
{
|
|
s.clear();
|
|
ch=getchar();
|
|
while(ch!='=') s+=ch,ch=getchar();
|
|
getstring(color_map[s]);
|
|
}
|
|
else if(s=="LabelMap")
|
|
{
|
|
s.clear();
|
|
ch=getchar();
|
|
while(ch!='=') s+=ch,ch=getchar();
|
|
getstring(label_map[s]);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr,R"(Error on line %d: "%s" is not a valid config item.
|
|
Valid config items: )",line,s.c_str());
|
|
vector<string> vec;
|
|
for(const auto &it:float_config_item) vec.push_back(it.first);
|
|
for(const auto &it:string_config_item) vec.push_back(it.first);
|
|
printlist(vec);
|
|
fprintf(stderr,".\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct vec
|
|
{
|
|
float x,y;
|
|
void operator += (vec a) {x+=a.x,y+=a.y;}
|
|
void operator -= (vec a) {x-=a.x,y-=a.y;}
|
|
void operator *= (float a) {x*=a,y*=a;}
|
|
vec operator + (vec a) const {vec b=(*this);b+=a;return b;}
|
|
vec operator - (vec a) const {vec b=(*this);b-=a;return b;}
|
|
vec operator * (float a) const {vec b=(*this);b*=a;return b;}
|
|
float norm() const {return sqrt(x*x+y*y);}
|
|
};
|
|
|
|
vec calc(vec a,vec b)
|
|
{
|
|
vec c=b-a;
|
|
c*=(vertex_R-border_width/2)/c.norm();
|
|
return a+c;
|
|
}
|
|
|
|
void printlabel(vec p,string s)
|
|
{
|
|
if(label_map.find(s)!=label_map.end()) s=label_map.at(s);
|
|
printf(R"(<text font-family="%s" fill="%s" font-size="%f" style="text-anchor: middle;"><tspan x="%f" y="%f">%s</tspan></text>
|
|
)", font_family.c_str(), font_color.c_str(), vertex_R, p.x, p.y+vertex_R*0.3, s.c_str());
|
|
}
|
|
|
|
int n,m;
|
|
float minX,minY,maxX,maxY;
|
|
string pc[N];
|
|
vec p[N];
|
|
|
|
void printhelp(char* name)
|
|
{
|
|
printf(
|
|
"g2s the 6east svg graph generator, built on %s.\n"
|
|
"Usage: %s <inputfile>\n"
|
|
,__DATE__,name);
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc,char** argv)
|
|
{
|
|
if(argc!=2) printhelp(argv[0]);
|
|
freopen(argv[1],"r",stdin);
|
|
|
|
init();
|
|
freopen(output_file.c_str(),"w",stdout);
|
|
vertex_R*=output_scale;
|
|
border_width*=output_scale;
|
|
|
|
cin>>n; //输入点数(int)
|
|
for(int i=1;i<=n;i++)
|
|
{
|
|
cin>>p[i].x>>p[i].y>>pc[i];
|
|
//输入第i个点的横坐标(float)、纵坐标(float)、半径(float)和颜色(string)
|
|
p[i].x*=output_scale,p[i].y*=output_scale;
|
|
if(Xdir=="left") p[i].x=-p[i].x;
|
|
if(Ydir=="up") p[i].y=-p[i].y;
|
|
if(color_map.find(pc[i])!=color_map.end()) pc[i]=color_map.find(pc[i])->second;
|
|
|
|
if(i==1) minX=maxX=p[i].x,minY=maxY=p[i].y;
|
|
if(p[i].x<minX) minX=p[i].x;
|
|
else if(p[i].x>maxX) maxX=p[i].x;
|
|
if(p[i].y<minY) minY=p[i].y;
|
|
else if(p[i].y>maxY) maxY=p[i].y;
|
|
}
|
|
if(output_shape=="square")
|
|
{
|
|
float delta=((maxX-minX)-(maxY-minY))*0.5;
|
|
if(delta>0) minY-=delta,maxY+=delta;
|
|
else delta=-delta,minX-=delta,maxX+=delta;
|
|
}
|
|
minX-=vertex_R,minY-=vertex_R;
|
|
maxX+=vertex_R,maxY+=vertex_R;
|
|
float X=minX-(maxX-minX)*XL;
|
|
float Y=minY-(maxY-minY)*YL;
|
|
for(int i=1;i<=n;i++) p[i].x-=X,p[i].y-=Y;
|
|
X=(maxX-X)+(maxX-minX)*XR;
|
|
Y=(maxY-Y)+(maxY-minY)*YR;
|
|
|
|
printf(R"(<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="%f" height="%f" viewBox="0 0 %f %f" version="1.1">
|
|
)", X, Y, X, Y);
|
|
|
|
for(int i=1;i<=n;i++)
|
|
{
|
|
printf(R"(<circle style="fill-rule:evenodd;fill:%s;fill-opacity:1;stroke-width:%f;stroke-linecap:square;stroke-linejoin:miter;stroke:%s;stroke-miterlimit:%f;" cx="%f" cy="%f" r="%f"/>
|
|
)",pc[i].c_str(),border_width,border_color.c_str(),border_width*0.7,p[i].x,p[i].y,vertex_R);
|
|
}
|
|
|
|
cin>>m; //输入边数(int)
|
|
for(int i=1;i<=m;i++)
|
|
{
|
|
int a,b;
|
|
cin>>a>>b; //输入端点编号(int[1,n])
|
|
vec A=calc(p[a],p[b]);
|
|
vec B=calc(p[b],p[a]);
|
|
printf(R"(<path style="fill:none;stroke-width:%f;stroke-linecap:butt;stroke-linejoin:miter;stroke:%s;stroke-miterlimit:%f;" d="M %f %f L %f %f "/>
|
|
)",border_width,border_color.c_str(),border_width*0.7,A.x,A.y,B.x,B.y);
|
|
}
|
|
|
|
if (label == "A" || label == "a") {
|
|
for (int i = 1; i <= n; ++i) {
|
|
printlabel(p[i],string{char(i + label[0] - 1)});
|
|
}
|
|
}
|
|
else if(label=="1")
|
|
{
|
|
for (int i = 1; i <= n; ++i) {
|
|
printlabel(p[i],to_string(i));
|
|
}
|
|
}
|
|
puts("</svg>");
|
|
return 0;
|
|
} |