/*************************** mincpp.C ****************************/ /* */ /* A program to minimize MD energy of polygonal knots. */ /* C++ version. Main difference is the vector operators. */ /* */ /********************** Ying-Qing Wu, 9/95 ***********************/ #include #include #include #include #define pprint(a,b) {fprintf(fp, a,b); printf(a,b);} #define print(a,b,c,d) {fprintf(fp,a,b,c,d); printf(a,b,c,d);} const int size = 1010; // max number of vertices const float minlambda = 0.01; float badrunlimit = 0.05; // change status if badrun exceed this*runnum int add_vtx = 0; // number of vertices to be added int printstyle = 0; // "1" to print also gradient and edge length float turnpoint = -1; char method = 'm'; FILE *fp; int runnum, vnum; struct vector { double coord[3]; double norm (void); double& operator [](int i) { return coord[i];} void fprint() { fprintf(fp, "%14.8f, %14.8f, %14.8f\n", coord[0],coord[1],coord[2]);} }; struct knots { vector* p; knots(void) { p = new vector[size]; } ~knots(void) { delete p;} vector& operator [](int i) { return p[i];} knots& operator =(knots& a) { for (int i=0; i1) strcpy(infile, argv[1]), getfile(); if (argc>2) strcpy(outfile, argv[2]); while (1) { printf("Enter a command (\"h\" for help): "); gets(cmd); switch (cmd[0]) { case 'h': help(); break; case 'q': return 0; case 'a': case 'd': if (cmd[0] == 'd') add_vtx = vnum; else if(sscanf(cmd, "%s %d", dumb, &add_vtx)<2) add_vtx = 0; add_vertex(); break; case 's': sscanf(cmd, "%s %d", dumb, &stdvnum); printf(" Min-dist energy: %14.8f\n", stdcirc(stdvnum)); printf(" Edge energy: %14.8f\n", enr_edge); printf(" Vertex energy: %14.8f\n", enr_vert); break; case 'f': sscanf(cmd, "%s %s %s", dumb, infile, outfile); getfile(); break; case 'r': if (sscanf(cmd, "%s %d", dumb, &runnum)==1) runnum = 0; run(); break; case 'm': method = (method == 'm') ? 'e' : 'm'; printf(" Set flow method to %c\n", method); break; case 'p': printstyle ^= 1; printf(" Set output style to %s print\n",style[printstyle]); break; case 't': sscanf(cmd, "%s %f", dumb, &turnpoint); printf(" Set turning point to %1.2f\n",turnpoint); break; default: printf("Wrong command. Please try again.\n"); break; } } } void help() { printf( "\nChoose one of the following:\n" " file knot1 knot2: set knot1 as input file and knot2 as output file\n" " run n: run the minimizer n times\n" " add n: add n vertices to the knot\n" " double: double the vertices, = add vert_number \n" " std n: compute the energy of a standard n-gon\n" " method: toggle flow method between MD grad and E grad\n" " pstyle: toggle between short (default) and long output\n" " tpoint x: set turning point to x (between 0 and 1)\n" " help: print this help menu\n" " quit: quit min\n" ); } void run() { int i,ctr,badrun; double move, temp, old_enr = 0, badlim, lambda=1; knots tempKnot; badlim = badrunlimit*runnum; printf(" \n Number of edges: %d\n", vnum); for (badrun = 0, ctr = 0; ctr=old_enr && ctr>1) badrun++; if (badrun>3*badlim && lambda > minlambda) { lambda = 0.9*lambda; badrun = int(2*badlim); } temp = (1.0*ctr)/runnum; printf("%-8d %14.8f \n", ctr, enr); old_enr = enr; findderiv(); for (i=0; i temp) move = lambda/derivative[i]; else move = lambda/maxderiv; knot[i] = knot[i] + (move * grad[i]); } } edgedist(); printf("%-8d %14.8f\n", ctr, enr); printfile(); } double min(int i, vector p, double& ratio) { vector e = p - knot[i]; ratio = (e * vtr[i])/(vtr[i] * vtr[i]); if (ratio < 0) ratio = 0; if (ratio > 1) ratio = 1; return (e - (ratio * vtr[i])).norm(); } void find_rate(int i, int j, double& rate_ij, double& rate_ji) { int k,n; double s[4], m[4], a, b, vv; vector v; if (method == 'e') { rate_ij = rate_ji = 0.5; return; } else if (i0 || j m[k]) n = k; // find n such that m[n] is minimal } if (n<2) rate_ij = s[n], rate_ji = n; else rate_ij = n-2, rate_ji = s[n]; } } } void edgedist(void) /* calculate rate, dist, and mindist */ { int i,j; double g_norm; mindist = maxgrad = enr = 0; for(i=0; i d) mindistance[n] = d; } if (d != 0) // compute the gradient: { vector v = (lenvtr[j]/(d*d*lenvtr[i])) * vtr[i]; double t = 2*lenvtr[i]*lenvtr[j]/(d*d*d*d); double r = (1-rate_ij)*t; vector minvtr = (knot[i] + rate_ij * vtr[i]) - (knot[j] + rate_ji * vtr[j]); grad[i] = grad[i] + v + (r * minvtr); grad[i+1] = grad[i+1] - v + ((t-r) * minvtr); int k = (j+1) % vnum; v = (lenvtr[i]/(d*d*lenvtr[j])) * vtr[j]; r = (1-rate_ji)*t; grad[j] = grad[j] + v - (r * minvtr); grad[k] = grad[k] - v - ((t-r) * minvtr); } } else d = 0; if (mindist == 0 || mindist > d && d != 0) mindist = d; if (d != 0) // compute the energy: enr += lenvtr[i]*lenvtr[j]/(d*d); } for (i=0; i 0) { j = (add_vtx > vnum) ? 0 : vnum - add_vtx; for (i = vnum-j; i > 0; i--) { if (i