Skip to content

Instantly share code, notes, and snippets.

@steveroush
Last active August 26, 2024 16:05
Show Gist options
  • Save steveroush/6938c45e62690033005a133a0534ef7f to your computer and use it in GitHub Desktop.
Save steveroush/6938c45e62690033005a133a0534ef7f to your computer and use it in GitHub Desktop.
Graphviz - round ortho edges
/*****************************************************
Name: roundedOrtho.gvpr
As of Date: 2024-08-25 20:24:11
Description: when possible, changes ortho edges to round the squared edges
Usage: dot -Gsplines=ortho myFile.gv | gvpr -cf roundedOrtho2.gvpr|neato -n2 -T...
Arguments: -Rnnn where nnn is the size of the rounding radius in points
*****************************************************/
/*******************************************************************************
equation for quarter circle came from:
https://mechanicalexpressions.com/explore/geometric-modeling/circle-spline-approximation.pdf
*******************************************************************************/
BEGIN{
int cnt, i, j, nextSeg, start, size, sizeM1, OK[], addSegment[];
float x1[],y1[],x2[],y2[], dx[], dy[], Radius, rndF;
string newPosStr, savePt, newPt[], oTok[int], help;
Radius=15.;
i=0;
while (i<ARGC) {
print("// ARG >", ARGV[i],"<");
if (ARGV[i]=="R") {
Radius=ARGV[++i];
} else if (ARGV[i]=="R*") {
Radius=substr(ARGV[i],1);
} else {
printf(2, help);
exit (1);
}
i++;
}
rndF=(Radius*(4*(-1+sqrt(2))/3));
print("// rndF: ",rndF);
//////////////////////////////////////////////////////////////
void doErr(string errString) {
print("// Error: ", errString);
printf(2,"Error: %s\n", errString);
}
//////////////////////////////////////////////////////////////
void doMsg(string errString) {
print("// Note: ", errString);
//printf(2,"Note: %s\n", errString);
}
/////////////////////////////////////////////////////////////
float Max(float f1, float f2) {
float fx;
if (f1>f2)
fx=f1;
else
fx=f2;
return fx;
}
////////////////////////////////////////////////////////////
float Min(float f1, float f2) {
float fx;
if (f1>f2)
fx=f2;
else
fx=f1;
return fx;
}
/////////////////////////////////////////////////////////////
float abs(float f1) {
float fx;
if (f1<0)
fx=-f1;
else
fx=f1;
return fx;
}
//////////////////////////////////////////////////////////////
// compute distance in points - always positive value
float distance(float X1,float Y1,float X2,float Y2) {
float di;
di=sqrt((X1-X2)*(X1-X2) + (Y1-Y2)*(Y1-Y2));
return di;
}
//////////////////////////////////////////////////////////////
string restring() {
int RI;
string RS;
RS="";
for (oTok[RI])
RS=RS + oTok[RI] + " ";
return(RS);
}
//////////////////////////////////////////////////////////////
void addPt(string aPt) {
newPosStr=newPosStr + aPt + " ";
}
//////////////////////////////////////////////////////////////
// shorten (by "cut") an end pt
string shorten(string fixedPt, string adjPt, float cut) {
float X1, Y1, X2, Y2, DX, DY;
string ts;
print("// fixedPt, adjPt: ", fixedPt, " ", adjPt);
X1=xOf(fixedPt);
Y1=yOf(fixedPt);
X2=xOf(adjPt);
Y2=yOf(adjPt);
DX=X2-X1;
DY=Y2-Y1;
print("// dx & dy: ", DX," ", DY);
if (abs(DX)>abs(DY)) {
if (DX>0)
X2-=cut;
else
X2+=cut;
} else {
if (DY>0)
Y2-=cut;
else
Y2+=cut;
}
ts=(string)X2 + "," + (string)Y2;
print("// from: ",adjPt);
print("// to: ",ts);
return(ts);
}
////////////////////////////////////////////////////////////
// recreate segment to make sure no intermediate points "overhang" end points
void adjust(int start, int stop, int setTo) {
int Indx;
for (Indx=start; Indx<=stop; Indx++) {
// adjust the position of oTok[Indx]
oTok[Indx]=oTok[setTo];
}
}
}
//////////////////////////////////////////////////////////////
BEG_G{
$.splines="";
}
E{
print("\n//",$.name);
unset(oTok);
$.oldPos=$.pos;
newPosStr="";
cnt=tokens($.pos,oTok);
if (cnt<7) { // single line segment, move on
print("// single line segment, SKIP");
//$.color="orange";
continue;
}
//$.color="green";
start=0;
for (i=0; i<=1; i++) {
if (oTok[i]=="[es]*") {
addPt(oTok[i]);
unset(oTok,i);
start++;
}
}
print("// cnt: ",cnt," start: ",start, " ", $.pos);
unset(x1);
unset(y1);
unset(x2);
unset(x2);
unset(dx);
unset(dy);
unset(newPt);
unset(addSegment);
i=start;
size=4;
sizeM1=size-1;
while(i<(cnt-2)) { ////// ??????
print("// toks: ", oTok[i]," ",oTok[i+sizeM1]);
x1[i]=xOf(oTok[i]);
y1[i]=yOf(oTok[i]);
x2[i]=xOf(oTok[i+sizeM1]);
y2[i]=yOf(oTok[i+sizeM1]);
dx[i]=x2[i]-x1[i];
dy[i]=y2[i]-y1[i];
print("// dx & dy: ",dx[i]," ",dy[i]);
if ((abs(dx[i])<.01 || abs(dy[i])<.01) && distance(x1[i],y1[i],x2[i],y2[i])>Radius) {
OK[i]=1;
print("// OK: ", i," ", oTok[i]," ",oTok[i+sizeM1]);
} else {
OK[i]=0;
print("// FAIL: ", i, " ", oTok[i]," ",oTok[i+sizeM1]);
}
i+=size;
size=3;
sizeM1=size-1;
}
// start over, look at two segments
print("\n// doit phase");
//addPt(oTok[start]);
i=start;
size=4;
sizeM1=size-1;
nextSeg=i+size;
while(i<(cnt-5)) { ////// ??????
print("// i: ", i, " OK & OK: ", OK[i], " ", OK[nextSeg]);
if (OK[i]==1 && OK[nextSeg]==1) {
savePt=oTok[i+sizeM1];
// adjust oTok[i+3] to shorten distance from oTok[i] to oTok[i+3] by Radius
oTok[i+sizeM1]=shorten(oTok[i], oTok[i+sizeM1], Radius);
print("// DEBUG #0: ", restring());
adjust(i+1, i+sizeM1-1, i);
print("// DEBUG #1: ", restring());
// now the next segment
print("// nextSeg, size: ", nextSeg," ",size);
oTok[nextSeg]=shorten(oTok[nextSeg+2], oTok[nextSeg], Radius);
adjust(nextSeg+1, nextSeg+1, nextSeg+2); // just adjust 1 point ??
print("// DEBUG #2: ", restring());
// now add the new segment
print("// adding: ", nextSeg, " ", oTok[nextSeg]);
addSegment[nextSeg]=1;
// re-do these 2 points to create quarter circle
newPt[nextSeg]=oTok[nextSeg-1];
newPt[nextSeg+1]=oTok[nextSeg];
newPt[nextSeg]=shorten(oTok[i], oTok[i+sizeM1], rndF);
newPt[nextSeg+1]=shorten(oTok[nextSeg+2], oTok[nextSeg], rndF);
newPt[nextSeg]=shorten(oTok[i], savePt, rndF);
newPt[nextSeg+1]=shorten(oTok[nextSeg+2], savePt, rndF);
newPt[nextSeg+2]=oTok[nextSeg];
print("// OK toks: ", oTok[i]," ",oTok[nextSeg]);
} else {
print("// FAIL toks: ", oTok[i]," ",oTok[nextSeg]);
}
i+=size;
size=3;
sizeM1=size-1;
nextSeg=i+size;
}
// finish
i=start;
//printf("// i: ");
while(i<cnt) { ////// ??????
//printf("%d ", i);
if (addSegment[i]!="") {
for (j=0; j<=2; j++) {
print("// i & j: ",i," ",j," ",newPt[i+j]);
addPt(newPt[i+j]);
}
}
addPt(oTok[i]);
i++;
}
printf("\n");
print("// orig: ", $.pos);
$.pos=newPosStr;
print("// new/improved: ",$.pos);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment