}
}
+static int vertex_in_triangles[N], vertex_in_triangles_checked;
+
static void addtriangle(int va, int vb, int vc) {
Triangle *t= &trisbuffer[ntris];
int k;
t->vertex[1][k]= conformation[vb][k];
t->vertex[2][k]= conformation[vc][k];
}
+ if (!vertex_in_triangles_checked) {
+ vertex_in_triangles[va]++;
+ vertex_in_triangles[vb]++;
+ vertex_in_triangles[vc]++;
+ }
displaylist[ntris++]= t;
}
static void generate_display_list(void) {
- int vb, ve[3], e;
+ int vb, ve[V6], e;
ntris= 0;
FOR_VERTEX(vb) {
- /* We use the two triangles in the parallelogram vb, vb+e0, vb+e1, vb+e2.
+ /* We use the two triangles in the parallelogram vb, vb+e5, vb+e0, vb+e1.
* We go round each triangle clockwise (although our surface is non-
- * orientable so it shouldn't matter).
+ * orientable so it shouldn't matter). Picking the parallelogram
+ * to our right avoids getting it wrong at the join.
*/
- for (e=0; e<3; e++) ve[e]= EDGE_END2(vb,e);
- if (ve[1]>=0) {
- if (ve[0]>=0) addtriangle(vb,ve[0],ve[1]);
- if (ve[2]>=0) addtriangle(vb,ve[1],ve[2]);
+ for (e=0; e<V6; e++) ve[e]= EDGE_END2(vb,e);
+ assert(ve[0]>=0);
+ if (ve[5]>=0) addtriangle(vb,ve[0],ve[5]);
+ if (ve[1]>=0) addtriangle(vb,ve[1],ve[0]);
+ }
+
+ if (!vertex_in_triangles_checked) {
+ int v, expd;
+ FOR_VERTEX(v) {
+ expd= RIM_VERTEX_P(v) ? 3 : 6;
+ if (vertex_in_triangles[v] != expd) {
+ fprintf(stderr,"vertex %02x used for %d triangles, expected %d\n",
+ v, vertex_in_triangles[v], expd);
+ abort();
+ }
}
+ vertex_in_triangles_checked= 1;
}
}
static DrawingMode dmred, dmblue, dmwhite;
static const DrawingMode *dmcurrent;
static int wwidth=WSZ, wheight=WSZ, wmindim=WSZ, wmaxdim=WSZ;
-static int ncut, currentbuffer, x11depth, x11screen;
+static int ncut, currentbuffer, x11depth, x11screen, wireframe;
XVisualInfo visinfo;
static double sizeadj_scale= 0.3, eyes_apart, scale_wmindim;
}
points[3]= points[0];
- XA( XFillPolygon(display,pixmap, dmcurrent->fillgc,
- points,3,Convex,CoordModeOrigin) );
+ if (!wireframe)
+ XA( XFillPolygon(display,pixmap, dmcurrent->fillgc,
+ points,3,Convex,CoordModeOrigin) );
XA( XDrawLines(display,pixmap, dmcurrent->linegc,
points, 4,CoordModeOrigin) );
}
typedef struct {
const char *name;
- void (*start)(void);
+ void (*start)(const XButtonEvent *e);
void (*delta)(double dx, double dy);
void (*conclude)(void);
void (*abandon)(void);
drag_##x##_conclude, drag_##x##_abandon \
}
-#define DRAG_SAVING(x, thing) \
+#define DRAG_SAVING(x, thing, hook) \
static typeof(thing) original_##thing; \
- static void drag_##x##_start(void) { \
+ static void drag_##x##_start(const XButtonEvent *e) { \
memcpy(&original_##thing, &thing, sizeof(thing)); \
+ hook; \
} \
static void drag_##x##_conclude(void) { } \
static void drag_##x##_abandon(void) { \
} \
DRAG(x)
-static void drag_none_start(void) { }
+static void drag_none_start(const XButtonEvent *e) { }
static void drag_none_delta(double dx, double dy) { }
static void drag_none_conclude(void) { }
static void drag_none_abandon(void) { }
}
#define PMATRIX(x) pmatrix(#x,x);
+static double drag_transform_conv_x_z= 0;
+static double drag_transform_conv_y_z= 0;
+
+static void drag_transform_prep(const XButtonEvent *e) {
+ static const double factor= 2.5;
+ drag_transform_conv_x_z= MAX( MIN(e->y * factor / wheight - (factor/2),
+ 1.0), -1.0);
+ drag_transform_conv_y_z= MAX( MIN(e->x * factor / wwidth - (factor/2),
+ 1.0), -1.0);
+ printf("drag_transform_conv_{x,y}_z = %g,%g\n",
+ drag_transform_conv_x_z, drag_transform_conv_y_z);
+}
+
+static void make_z_rotation(double rotz[D3][D3], double cz, double sz) {
+ rotz[0][0]= cz; rotz[0][1]= sz; rotz[0][2]= 0;
+ rotz[1][0]= -sz; rotz[1][1]= cz; rotz[1][2]= 0;
+ rotz[2][0]= 0; rotz[2][1]= 0; rotz[2][2]= 1;
+}
+
static void drag_rotate_delta(double dx, double dy) {
/* We multiple our transformation matrix by a matrix:
*
* we make cy and sy be cos() and sin(hypot(x,y)) and use
* with cr,sr as cos() and sin(atan2(y,y)):
*
- * Ie we would do T' = R^T X R T where
- * or T' = C T where C = R^T X R and
+ * Ie we would do T' = Z R^T X R T where
+ * or T' = Z C T where C = R^T X R and
*
* adjustment R = [ cr sr 0 ]
* [ -sr cr 0 ]
- * [ 0 0 1 ]
+ * [ 0 0 1 ] or make_z_rotation(cr,sr)
+ *
+ * rotation Z = [ cz sz 0 ]
+ * [ -sz cz 0 ]
+ * [ 0 0 1 ] or make_z_rotation(cz,sz)
*/
- double rotx[D3][D3], adjr[D3][D3];
+ double rotx[D3][D3], adjr[D3][D3], rotz[D3][D3];
GSL_MATRIX(rotx);
GSL_MATRIX(adjr);
+ GSL_MATRIX(rotz);
static double temp[D3][D3], change[D3][D3];
static GSL_MATRIX(temp);
static GSL_MATRIX(change);
+ printf("\nTRANSFORM %g, %g\n", dx,dy);
+
+ double dz= -drag_transform_conv_x_z * dx +
+ drag_transform_conv_y_z * dy;
+
+ dx *= (1 - fabs(drag_transform_conv_x_z));
+ dy *= (1 - fabs(drag_transform_conv_y_z));
+
double d= hypot(dx,dy);
- if (d < 1e-6) return;
+
+ printf(" dx,dy,dz = %g, %g, %g d = %g\n", dx,dy,dz, d);
+
+ if (hypot(d,dz) < 1e-6) return;
+
+ printf(" no xy rotation\n");
double ang= d*2.0;
double cy= cos(ang);
double sy= sin(ang);
- double cr= -dy / d;
- double sr= dx / d;
+
+ double cr, sr;
+ if (d > 1e-6) {
+ cr= -dy / d;
+ sr= dx / d;
+ } else {
+ cr= 1;
+ sr= 0;
+ }
printf("\n d=%g cy,sy=%g,%g cr,sr=%g,%g\n\n", d,cy,sy,cr,sr);
rotx[0][0]= 1; rotx[0][1]= 0; rotx[0][2]= 0;
rotx[2][0]= 0; rotx[2][1]= -sy; rotx[2][2]= cy;
PMATRIX(rotx);
- adjr[0][0]= cr; adjr[0][1]= sr; adjr[0][2]= 0;
- adjr[1][0]= -sr; adjr[1][1]= cr; adjr[1][2]= 0;
- adjr[2][0]= 0; adjr[2][1]= 0; adjr[2][2]= 1;
+ make_z_rotation(adjr,cr,sr);
PMATRIX(adjr);
GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
&rotx_gsl,&adjr_gsl,
0.0, &temp_gsl) );
- PMATRIX(temp);
+ pmatrix("X R", temp);
GA( gsl_blas_dgemm(CblasTrans,CblasNoTrans, 1.0,
&adjr_gsl,&temp_gsl,
0.0, &change_gsl) );
PMATRIX(change);
+ double angz= dz*2.0;
+ make_z_rotation(rotz,cos(angz),sin(angz));
+ PMATRIX(rotz);
+
+ GA( gsl_blas_dgemm(CblasTrans,CblasNoTrans, 1.0,
+ &rotz_gsl,&change_gsl,
+ 0.0, &temp_gsl) );
+ pmatrix("Z C", temp);
+
static double skew[D3][D3];
static GSL_MATRIX(skew);
GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
- &change_gsl,&transform_gsl,
+ &temp_gsl, &transform_gsl,
0.0, &skew_gsl) );
PMATRIX(skew);
printf("drag_rotate_delta...\n");
show();
}
-DRAG_SAVING(rotate, transform);
+DRAG_SAVING(rotate, transform, drag_transform_prep(e));
static void drag_sizeadj_delta(double dx, double dy) {
sizeadj_scale *= pow(3.0, -dy);
show();
}
-DRAG_SAVING(sizeadj, sizeadj_scale);
+DRAG_SAVING(sizeadj, sizeadj_scale, );
static void drag_3d_delta(double dx, double dy) {
eyes_apart += dx * 0.1;
printf("sizeadj eyes_apart %g\n", eyes_apart);
show();
}
-DRAG_SAVING(3d, eyes_apart);
+DRAG_SAVING(3d, eyes_apart, );
static const Drag *drag= &drag_none;
drag->name, (unsigned long)e->button, e->x, e->y);
drag_last_x= e->x;
drag_last_y= e->y;
- drag->start();
+ drag->start(e);
}
if (e->type == ButtonRelease) {
printf("drag=%s release %d,%d\n", drag->name, e->x, e->y);
}
if (!strcmp(buf,"q")) exit(0);
+ if (!strcmp(buf,"w")) {
+ wireframe= !wireframe;
+ show();
+ return;
+ }
if (!strcmp(buf,"d")) {
eyes_apart= eyes_apart>0 ? eyes_apart_min : eyes_apart_preferred;
show();
show();
}
+static void topocheck(void) {
+ int v1,e,v2,eprime,v1prime, count;
+ FOR_EDGE(v1,e,v2) {
+ count= 0;
+ FOR_VEDGE(v2,eprime,v1prime)
+ if (v1prime==v1) count++;
+ if (count!=1) {
+ fprintf(stderr,"%02x -%d-> %02x reverse edge count = %d!\n",
+ v1,e,v2, count);
+ FOR_VEDGE(v2,eprime,v1prime)
+ fprintf(stderr,"%02x -%d-> %02x -> %d -> %02x\n",
+ v1,e,v2,eprime,v1prime);
+ exit(-1);
+ }
+ }
+}
+
int main(int argc, const char *const *argv) {
static const int wantedevents= POLLIN|POLLPRI|POLLERR|POLLHUP;
int k, i, r, *xfds, nxfds, polls_alloc=0;
struct pollfd *polls=0;
int motion_deferred=0, motion_x=-1, motion_y=-1;
+
+ topocheck();
+ if (argc==1) { printf("topology self-consistent, ok\n"); exit(0); }
if (argc != 2 || argv[1][0]=='-') {
fputs("need filename\n",stderr); exit(8);