Last active
August 26, 2024 16:05
-
-
Save steveroush/6938c45e62690033005a133a0534ef7f to your computer and use it in GitHub Desktop.
Graphviz - round ortho edges
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************************************************** | |
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