/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ /*********************************************************************/ /* (c) COPYRIGHT International Business Machines Corp. 1995 */ /* ALL RIGHTS RESERVED */ /*********************************************************************/ #include #include /* "how" as a number doesn't seem very easy to use, but * i don't have a great alternate suggestion. */ typedef struct taskarg { Object o; /* data to work on */ int how; /* 0 to 7, arbitrary reorientations */ int partitioned; /* if set, f is part of a partitioned field */ int maxextent[2]; /* total mesh size for partitioned images */ int count[2]; /* x and y counts */ int grid; /* what original grid was like */ int altergrid; /* how the grid needs to be altered */ int alterdata; /* ditto for data; see INV_xxx flags below */ int dotodata; /* the actual transform to the data - depends on interaction between altergrid & alterdata */ } Rtaskarg; static Error DoImage (Pointer); static Error ReorientImage (Rtaskarg *t); static Error setextents(Object, int *); static Error dogrid (Rtaskarg *tp); static Error dodata (Rtaskarg *tp); #if 0 /* set this if you want to run serial instead of parallel */ #define SERIAL 1 #endif Error m_Reorient(Object *in, Object *out) { Class c; Rtaskarg *t; if (!in[0]) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "image"); return ERROR; } c = DXGetObjectClass(in[0]); if (c != CLASS_GROUP && c != CLASS_FIELD) { DXSetError(ERROR_BAD_PARAMETER, "#10190", "image"); return ERROR; } /* initial values all 0 */ t = (Rtaskarg *)DXAllocateZero(sizeof(Rtaskarg)); if (!t) return ERROR; /* default is to ensure that the image is oriented in the manner * the Display() module prefers. */ if (in[1] && (!DXExtractInteger(in[1], &t->how) || t->how < 0 || t->how > 7)) { DXSetError(ERROR_BAD_PARAMETER, "#10040", "how", 0, 7); goto error; } t->o = (Object)DXCopy(in[0], COPY_STRUCTURE); if (!t->o) goto error; #if !SERIAL if (!(DXCreateTaskGroup())) goto error; #endif if (!ReorientImage(t)) goto error; #if !SERIAL if (!(DXExecuteTaskGroup())) goto error; #endif /* successful return */ out[0] = t->o; return OK; error: DXDelete(t->o); DXFree((Pointer)t); return ERROR; } extern Error ReorientImage(Rtaskarg *t) { Object subo; Class class; int i; Rtaskarg nt; memcpy((char *)&nt, (char *)t, sizeof(Rtaskarg)); class = DXGetObjectClass(t->o); if (class == CLASS_GROUP) class = DXGetGroupClass((Group)t->o); switch (class) { case CLASS_COMPOSITEFIELD: /* put this in a subroutine */ if (setextents(t->o, (int *)&nt.maxextent) == ERROR) goto error; nt.partitioned = 1; for (i=0; subo = DXGetEnumeratedMember((Group)t->o, i, NULL); i++) { nt.o = subo; if (!ReorientImage(&nt)) goto error; } break; case CLASS_GROUP: for (i=0; subo = DXGetEnumeratedMember((Group)t->o, i, NULL); i++) { nt.o = subo; if (!ReorientImage(&nt)) goto error; } break; case CLASS_FIELD: nt.o = t->o; #if !SERIAL if (!DXAddTask(DoImage, (Pointer)&nt, sizeof(nt), 1.0)) goto error; #else if (!DoImage(&nt)) goto error; #endif break; default: /* set an error here? bad object type? */ break; } return OK; error: return ERROR; } static Error setextents(Object o, int *e) { Object subo; Array a; int i, dim; int mo[2]; int counts[2]; /* gag. i'm going to have to look for partitioned images here * and treat them special. oh boy. */ for (i=0; subo = DXGetEnumeratedMember((Group)o, i, NULL); i++) { if (DXGetObjectClass(subo) != CLASS_FIELD) { DXSetError(ERROR_INVALID_DATA, "member of partitioned field is not a field"); return ERROR; } a = (Array)DXGetComponentValue((Field)subo, "connections"); if (!a) { DXSetError(ERROR_INVALID_DATA, "field has no `connections' component"); return ERROR; } if (DXGetObjectClass((Object)a) != CLASS_ARRAY) { DXSetError(ERROR_INVALID_DATA, "connections component is not an Array object"); return ERROR; } if ((DXQueryGridConnections(a, &dim, NULL) == ERROR) || (dim != 2)) { DXSetError(ERROR_INVALID_DATA, "field must have regular 2d connections"); return ERROR; } DXQueryGridConnections(a, &dim, counts); if (!DXGetMeshOffsets((MeshArray)a, mo)) return ERROR; if (mo[0] + counts[0] > e[0]) e[0] = mo[0] + counts[0]; if (mo[1] + counts[1] > e[1]) e[1] = mo[1] + counts[1]; } return OK; } /* two issues: what to do with the data, and what to do * with the origins & deltas which define the grid. */ /* settings for the "alter" flags below */ #define INV_NOTHING 0x00 /* already correct order */ #define INV_TRANSPOSE 0x01 /* transpose x and y data */ #define INV_ROWS 0x02 /* invert the data inside each row */ #define INV_COLS 0x04 /* same w/ cols */ #define INV_EXCHANGE 0x08 /* exchange the x and y axis */ /* settings for the grid flag */ #define Y_FASTEST 0x01 /* y variables are contig in memory */ #define NEGATIVE_X 0x02 /* deltas from positions array */ #define NEGATIVE_Y 0x04 /* ditto */ static Error DoImage (Pointer ptr) { Rtaskarg *tp = (Rtaskarg *)ptr; if (dogrid(tp) == ERROR) return ERROR; return OK; } static Error dogrid (Rtaskarg *tp) { Field field; Array positions, connections, a; Array new_positions=NULL; Array new_connections=NULL; int yfastest = 0; int negative_x = 0; int negative_y = 0; int xcounts, ycounts; int i, dim, counts[2], itemp; int meshextents[2]; float origin[2], deltas[4], ftemp; int otherdim; field = (Field)tp->o; /* get partition info here because i'll have to deal * with fixing up the mesh offsets as well. */ connections = (Array) DXGetComponentValue(field, "connections"); if (!connections) { DXSetError(ERROR_MISSING_DATA, "field has no `connections' component"); return ERROR; } if ((!DXQueryGridConnections(connections, &dim, NULL)) || (dim != 2)) { DXSetError(ERROR_INVALID_DATA, "connections must be a 2D regular grid"); goto error; } if (!DXGetMeshOffsets((MeshArray)connections, (int *)meshextents)) return ERROR; /* now we have the start of this grid in meshextents and the extents * of all the partitioned fields combined in tp->maxextents */ #if 0 DXMessage("old extents: %d %d, %d %d", meshextents[0], meshextents[1], tp->maxextent[0], tp->maxextent[1]); #endif /* verify the positions are regular and 2d */ positions = (Array) DXGetComponentValue(field, "positions"); if (!positions) { DXSetError(ERROR_MISSING_DATA, "field has no `positions' component"); return ERROR; } if ((!DXQueryGridPositions(positions, &dim, counts, origin, deltas)) || dim != 2) { DXSetError(ERROR_INVALID_DATA, "positions must be a 2D regular grid"); goto error; } /* decide what to do with the grid */ /* figure out what the orientation of the input image was; we want * the output deltas to be positive with x varies fastest. figure * out what has to happen to the data to make that happen, and * then figure out what additional thing has to happen to the * data to change the orientation as the user requested. */ if (deltas[3] != 0) { yfastest++; tp->grid |= Y_FASTEST; tp->altergrid |= INV_EXCHANGE | INV_TRANSPOSE; } else if (deltas[2] != 0) { yfastest = 0; } else { DXSetError(ERROR_INVALID_DATA, "image must have an orthogonal grid"); goto error; } if (deltas[0] < 0 || deltas[2] < 0) { negative_x++; tp->grid |= NEGATIVE_X; tp->altergrid |= INV_COLS; } if (deltas[1] < 0 || deltas[3] < 0) { negative_y++; tp->grid |= NEGATIVE_Y; tp->altergrid |= INV_ROWS; } tp->count[0] = counts[0]; tp->count[1] = counts[1]; /* above this line is all setup; below this line the field is changed */ /* first do the data, then do the grid. * this is because depending on what "how" is, this subroutine * might change the "altergrid" setting. */ if (dodata(tp) == ERROR) goto error; /* only do the stuff below if there is something to do */ if (tp->grid == 0 && tp->altergrid == 0 && tp->dotodata == 0) { if (!DXEndField(field)) return ERROR; return OK; } /* hack because i can't get the logic behind this right. */ otherdim = 0; /* DXMessage("grid = %d, how now = %d\n", tp->altergrid, tp->how); */ switch (tp->altergrid) { case 0: if (tp->how == 4 || tp->how == 6) otherdim++; break; case 1: if (tp->how == 1 || tp->how == 3) otherdim++; break; case 2: if (tp->how == 0 || tp->how == 2) otherdim++; break; case 3: if (tp->how == 5 || tp->how == 7) otherdim++; break; case 4: if (tp->how == 0 || tp->how == 2) otherdim++; break; case 5: if (tp->how == 5 || tp->how == 7) otherdim++; break; case 6: if (tp->how == 4 || tp->how == 6) otherdim++; break; case 7: if (tp->how == 1 || tp->how == 3) otherdim++; break; } /* now fix the counts and deltas to match the order the * Display module is most comfortable with. */ if (tp->altergrid & INV_COLS) { origin[0] += deltas[0] * (counts[0]-1) + deltas[2] * (counts[1]-1); if (deltas[0] != 0.0) deltas[0] = -deltas[0]; if (deltas[2] != 0.0) deltas[2] = -deltas[2]; } if (tp->dotodata & INV_COLS) { if (otherdim) meshextents[1] = tp->maxextent[1] - counts[1] - meshextents[1]; else meshextents[0] = tp->maxextent[0] - counts[0] - meshextents[0]; } if (tp->altergrid & INV_ROWS) { origin[1] += deltas[1] * (counts[0]-1) + deltas[3] * (counts[1]-1); if (deltas[1] != 0.0) deltas[1] = -deltas[1]; if (deltas[3] != 0.0) deltas[3] = -deltas[3]; } if (tp->dotodata & INV_ROWS) { if (otherdim) meshextents[0] = tp->maxextent[0] - counts[0] - meshextents[0]; else meshextents[1] = tp->maxextent[1] - counts[1] - meshextents[1]; } if (tp->altergrid & INV_TRANSPOSE) { ftemp = deltas[2]; deltas[2] = deltas[0]; deltas[0] = ftemp; ftemp = deltas[3]; deltas[3] = deltas[1]; deltas[1] = ftemp; } if (tp->altergrid & INV_EXCHANGE) { itemp = counts[0]; counts[0] = counts[1]; counts[1] = itemp; } if (tp->dotodata & INV_TRANSPOSE) { itemp = meshextents[0]; meshextents[0] = meshextents[1]; meshextents[1] = itemp; } #if 0 DXMessage("new extents: %d %d", meshextents[0], meshextents[1]); #endif /* redo the positions component */ new_positions = DXMakeGridPositionsV(2, counts, origin, deltas); if (!new_positions) goto error; /* redo the connections component */ new_connections = DXMakeGridConnectionsV(2, counts); if (!new_connections) goto error; /* and for partitioned data, fix the mesh extents */ if (tp->partitioned) { if (!DXSetMeshOffsets((MeshArray)new_connections, (int *)meshextents)) return ERROR; } /* place in field */ if (!DXSetComponentValue(field, "positions", (Object)new_positions)) goto error; if (!DXSetComponentValue(field, "connections", (Object)new_connections)) goto error; if (!DXChangedComponentValues(field, "positions")) goto error; if (!DXChangedComponentValues(field, "connections")) goto error; if (!DXEndField(field)) goto error; return OK; error: DXDelete((Object)new_positions); DXDelete((Object)new_connections); return ERROR; } #define MAXSHAPE 64 static Error dodata (Rtaskarg *tp) { Field field; Array a, new_a = NULL; int yfastest; int negative_x; int negative_y; int loopcount[2]; int cnum; int invert; Pointer fromptr, toptr; int size; ubyte *from1, *to1; int *from4, *to4; typedef struct { ubyte _u[3]; } threebytes; threebytes *from3, *to3; typedef struct { int _i[3]; } twelvebytes; twelvebytes *from12, *to12; int i, ii, j, jj, k; char *name, *dattr, *rattr; int nodeps, norefs; int items; Type type; Category cat; int rank, shape[MAXSHAPE]; int didwork; field = (Field)tp->o; yfastest = tp->grid & Y_FASTEST; negative_x = tp->grid & NEGATIVE_X; negative_y = tp->grid & NEGATIVE_Y; #if 1 /* in again */ /*xxx out for now */ #if 0 DXMessage("yfastest = %d, neg_x = %d, neg_y = %d", yfastest, negative_x, negative_y); #endif /* take care of all the possibilities; inverted axis and * different data orientations. alter tp->how to make it match * what happens with the x-fastest, positive x & y deltas. */ if (tp->how != 0) { invert = tp->grid & Y_FASTEST ? 1 : 0; invert += tp->grid & NEGATIVE_X ? 1 : 0; invert += tp->grid & NEGATIVE_Y ? 1 : 0; switch (invert) { case 2: switch (tp->how) { case 4: tp->how = 7; break; case 5: tp->how = 4; break; case 6: tp->how = 5; break; case 7: tp->how = 6; break; } break; case 1: case 3: switch (tp->how) { case 1: tp->how = 3; break; case 3: tp->how = 1; break; case 5: tp->how = 6; break; case 6: tp->how = 5; break; case 4: tp->how = 7; break; case 7: tp->how = 4; break; } break; } } /* now that we know something about how the input image is * oriented, see how the user wants it to go out. */ switch (tp->how) { case 0: /* just make the image in the order the Display module * is happiest handling. */ break; case 4: tp->alterdata |= (yfastest ? INV_ROWS : INV_COLS); break; case 6: tp->alterdata |= (yfastest ? INV_COLS : INV_ROWS); break; case 2: tp->alterdata |= INV_ROWS; tp->alterdata |= INV_COLS; break; case 7: tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= INV_TRANSPOSE; break; case 3: tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= INV_TRANSPOSE; tp->alterdata |= (yfastest ? INV_ROWS : INV_COLS); break; case 1: tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= INV_TRANSPOSE; tp->alterdata |= (yfastest ? INV_COLS : INV_ROWS); break; case 5: tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= INV_TRANSPOSE; tp->alterdata |= INV_ROWS; tp->alterdata |= INV_COLS; break; } /* now compare what happens to the grid vs data. if we're * moving the grid we can leave the data alone; if we are * not moving the grid we have to move the data. */ if ((tp->altergrid & INV_TRANSPOSE) ^ (tp->alterdata & INV_TRANSPOSE)) tp->dotodata |= INV_TRANSPOSE; if ((tp->altergrid & INV_ROWS) ^ (tp->alterdata & INV_ROWS)) tp->dotodata |= INV_ROWS; if ((tp->altergrid & INV_COLS) ^ (tp->alterdata & INV_COLS)) tp->dotodata |= INV_COLS; #else switch (tp->how) { case 0: /* just make the image in the order the Display module * is happiest handling. */ break; case 4: tp->alterdata |= INV_COLS; break; case 6: tp->alterdata |= INV_ROWS; break; case 2: tp->alterdata |= INV_ROWS | INV_COLS; break; #define FLIP(what) ((tp->altergrid & (what)) ^ (what)) case 7: #if 0 tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= FLIP (INV_TRANSPOSE); #endif tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE; break; case 3: #if 0 tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= FLIP (INV_TRANSPOSE | INV_COLS); #endif tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE | INV_COLS; break; case 1: #if 0 tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= FLIP (INV_TRANSPOSE | INV_ROWS); #endif tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE | INV_ROWS; break; case 5: #if 0 tp->altergrid ^= INV_EXCHANGE; tp->alterdata |= FLIP (INV_TRANSPOSE | INV_ROWS | INV_COLS); #endif tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE | INV_ROWS | INV_COLS; break; } #if 0 DXMessage("before grid = 0x%04x, data = 0x%04x", tp->altergrid, tp->alterdata); #endif #define TOGGLE(what, what1, bits) (what ^= (what1 & bits)) TOGGLE(tp->altergrid, tp->alterdata, INV_EXCHANGE); tp->alterdata &= ~INV_EXCHANGE; TOGGLE(tp->alterdata, tp->altergrid, INV_TRANSPOSE); TOGGLE(tp->alterdata, tp->altergrid, INV_ROWS); TOGGLE(tp->alterdata, tp->altergrid, INV_COLS); #if 0 DXMessage("after grid = 0x%04x, data = 0x%04x", tp->altergrid, tp->alterdata); #endif #endif #if 0 DXMessage("altergrid = %d, alterdata = %d, dotodata = %d", tp->altergrid, tp->alterdata, tp->dotodata); #endif /* if we don't have to change the data in the components, we're done */ if (tp->dotodata == INV_NOTHING) return OK; for (cnum = 0; a = (Array)DXGetEnumeratedComponentValue(field, cnum, &name); cnum++) { if (!strcmp(name, "positions") || !strcmp(name, "connections")) continue; /* if no deps and no refs, just pass this component through untouched. */ nodeps = 0; dattr = NULL; if (!DXGetStringAttribute((Object)a, "dep", &dattr) || !dattr) nodeps++; norefs = 0; rattr = NULL; if (!DXGetStringAttribute((Object)a, "ref", &rattr) || !rattr) norefs++; if (nodeps && norefs) continue; if (dattr && strcmp(dattr, "positions") && strcmp(dattr, "connections")) continue; if (nodeps && !norefs) { /* this is not dep anything but is ref something. to do this * right, i need to reorder the refs the same way i reorder * the target. i don't have the code to do this written, but * i've got it in slab/slice and other places. */ continue; } /* ok, we got a live one */ if (!strcmp(dattr, "positions")) { loopcount[0] = tp->count[0]; loopcount[1] = tp->count[1]; } else { loopcount[0] = tp->count[0] - 1; loopcount[1] = tp->count[1] - 1; } size = DXGetItemSize(a); fromptr = DXGetArrayData(a); if (!fromptr) goto error; if (!DXGetArrayInfo(a, &items, &type, &cat, &rank, shape)) goto error; new_a = DXNewArrayV(type, cat, rank, shape); if (!new_a) goto error; if (!DXAddArrayData(new_a, 0, items, NULL)) goto error; toptr = DXGetArrayData(new_a); if (!toptr) goto error; #define MOVEDATA1(op, np) \ \ if (tp->dotodata == INV_TRANSPOSE) { \ for (i=0; idotodata == INV_ROWS) { \ for (i=0; idotodata == INV_COLS) { \ for (i=0, ii=loopcount[1]-1; idotodata == (INV_COLS|INV_ROWS)) { \ for (i=0, ii=loopcount[1]-1; idotodata == (INV_TRANSPOSE|INV_COLS)) { \ for (i=0; idotodata == (INV_TRANSPOSE|INV_ROWS)) { \ for (i=0, ii=loopcount[1]-1; idotodata == (INV_TRANSPOSE|INV_COLS|INV_ROWS)) { \ for (i=0, ii=loopcount[1]-1; idotodata == INV_TRANSPOSE) { \ for (i=0; idotodata == INV_ROWS) { \ for (i=0; idotodata == INV_COLS) { \ for (i=0, ii=loopcount[1]-1; idotodata == (INV_COLS|INV_ROWS)) { \ for (i=0, ii=loopcount[1]-1; idotodata == (INV_TRANSPOSE|INV_COLS)) { \ for (i=0; idotodata == (INV_TRANSPOSE|INV_ROWS)) { \ for (i=0, ii=loopcount[1]-1; idotodata == (INV_TRANSPOSE|INV_COLS|INV_ROWS)) { \ for (i=0, ii=loopcount[1]-1; i