1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8 /*********************************************************************/
9 /* (c) COPYRIGHT International Business Machines Corp. 1995 */
10 /* ALL RIGHTS RESERVED */
11 /*********************************************************************/
12
13 #include <dxconfig.h>
14
15 #if defined(HAVE_STRING_H)
16 #include <string.h>
17 #endif
18
19 #include <dx/dx.h>
20
21
22 /* "how" as a number doesn't seem very easy to use, but
23 * i don't have a great alternate suggestion.
24 */
25 typedef struct taskarg {
26 Object o; /* data to work on */
27 int how; /* 0 to 7, arbitrary reorientations */
28 int partitioned; /* if set, f is part of a partitioned field */
29 int maxextent[2]; /* total mesh size for partitioned images */
30 int count[2]; /* x and y counts */
31 int grid; /* what original grid was like */
32 int altergrid; /* how the grid needs to be altered */
33 int alterdata; /* ditto for data; see INV_xxx flags below */
34 int dotodata; /* the actual transform to the data - depends on
35 interaction between altergrid & alterdata */
36 } Rtaskarg;
37
38 static Error DoImage (Pointer);
39 static Error ReorientImage (Rtaskarg *t);
40
41 static Error setextents(Object, int *);
42 static Error dogrid (Rtaskarg *tp);
43 static Error dodata (Rtaskarg *tp);
44
45 #if 0 /* set this if you want to run serial instead of parallel */
46 #define SERIAL 1
47 #endif
48
m_Reorient(Object * in,Object * out)49 Error m_Reorient(Object *in, Object *out)
50 {
51
52 Class c;
53 Rtaskarg *t;
54
55
56 if (!in[0]) {
57 DXSetError(ERROR_BAD_PARAMETER, "#10000", "image");
58 return ERROR;
59 }
60
61 c = DXGetObjectClass(in[0]);
62 if (c != CLASS_GROUP && c != CLASS_FIELD) {
63 DXSetError(ERROR_BAD_PARAMETER, "#10190", "image");
64 return ERROR;
65 }
66
67 /* initial values all 0 */
68 t = (Rtaskarg *)DXAllocateZero(sizeof(Rtaskarg));
69 if (!t)
70 return ERROR;
71
72 /* default is to ensure that the image is oriented in the manner
73 * the Display() module prefers.
74 */
75 if (in[1] && (!DXExtractInteger(in[1], &t->how) || t->how < 0 || t->how > 7)) {
76 DXSetError(ERROR_BAD_PARAMETER, "#10040", "how", 0, 7);
77 goto error;
78 }
79
80
81 t->o = (Object)DXCopy(in[0], COPY_STRUCTURE);
82 if (!t->o)
83 goto error;
84
85 #if !SERIAL
86 if (!(DXCreateTaskGroup()))
87 goto error;
88 #endif
89
90 if (!ReorientImage(t))
91 goto error;
92
93 #if !SERIAL
94 if (!(DXExecuteTaskGroup()))
95 goto error;
96 #endif
97
98 /* successful return */
99 out[0] = t->o;
100 return OK;
101
102 error:
103 DXDelete(t->o);
104 DXFree((Pointer)t);
105 return ERROR;
106 }
107
108
109
110 static Error
ReorientImage(Rtaskarg * t)111 ReorientImage(Rtaskarg *t)
112 {
113 Object subo;
114 Class class;
115 int i;
116 Rtaskarg nt;
117
118 memcpy((char *)&nt, (char *)t, sizeof(Rtaskarg));
119
120 class = DXGetObjectClass(t->o);
121 if (class == CLASS_GROUP)
122 class = DXGetGroupClass((Group)t->o);
123
124 switch (class) {
125 case CLASS_COMPOSITEFIELD:
126 /* put this in a subroutine */
127
128 if (setextents(t->o, (int *)&nt.maxextent) == ERROR)
129 goto error;
130
131 nt.partitioned = 1;
132 for (i=0; (subo = DXGetEnumeratedMember((Group)t->o, i, NULL)); i++) {
133 nt.o = subo;
134 if (!ReorientImage(&nt))
135 goto error;
136 }
137 break;
138
139 case CLASS_GROUP:
140 for (i=0; (subo = DXGetEnumeratedMember((Group)t->o, i, NULL)); i++) {
141 nt.o = subo;
142 if (!ReorientImage(&nt))
143 goto error;
144 }
145 break;
146
147 case CLASS_FIELD:
148 nt.o = t->o;
149 #if !SERIAL
150 if (!DXAddTask(DoImage, (Pointer)&nt, sizeof(nt), 1.0))
151 goto error;
152 #else
153 if (!DoImage(&nt))
154 goto error;
155
156 #endif
157 break;
158
159 default:
160 /* set an error here? bad object type? */
161 break;
162
163 }
164
165 return OK;
166
167 error:
168 return ERROR;
169
170 }
171
setextents(Object o,int * e)172 static Error setextents(Object o, int *e)
173 {
174 Object subo;
175 Array a;
176 int i, dim;
177 int mo[2];
178 int counts[2];
179
180 /* gag. i'm going to have to look for partitioned images here
181 * and treat them special. oh boy.
182 */
183 for (i=0; (subo = DXGetEnumeratedMember((Group)o, i, NULL)); i++) {
184
185 if (DXGetObjectClass(subo) != CLASS_FIELD) {
186 DXSetError(ERROR_DATA_INVALID,
187 "member of partitioned field is not a field");
188 return ERROR;
189 }
190
191 a = (Array)DXGetComponentValue((Field)subo, "connections");
192 if (!a) {
193 DXSetError(ERROR_DATA_INVALID,
194 "field has no `connections' component");
195 return ERROR;
196 }
197 if (DXGetObjectClass((Object)a) != CLASS_ARRAY) {
198 DXSetError(ERROR_DATA_INVALID,
199 "connections component is not an Array object");
200 return ERROR;
201 }
202
203 if ((DXQueryGridConnections(a, &dim, NULL) == ERROR) ||
204 (dim != 2)) {
205 DXSetError(ERROR_DATA_INVALID,
206 "field must have regular 2d connections");
207 return ERROR;
208 }
209 DXQueryGridConnections(a, &dim, counts);
210
211 if (!DXGetMeshOffsets((MeshArray)a, mo))
212 return ERROR;
213
214 if (mo[0] + counts[0] > e[0])
215 e[0] = mo[0] + counts[0];
216 if (mo[1] + counts[1] > e[1])
217 e[1] = mo[1] + counts[1];
218 }
219
220 return OK;
221 }
222
223
224 /* two issues: what to do with the data, and what to do
225 * with the origins & deltas which define the grid.
226 */
227
228 /* settings for the "alter" flags below */
229 #define INV_NOTHING 0x00 /* already correct order */
230 #define INV_TRANSPOSE 0x01 /* transpose x and y data */
231 #define INV_ROWS 0x02 /* invert the data inside each row */
232 #define INV_COLS 0x04 /* same w/ cols */
233 #define INV_EXCHANGE 0x08 /* exchange the x and y axis */
234
235 /* settings for the grid flag */
236 #define Y_FASTEST 0x01 /* y variables are contig in memory */
237 #define NEGATIVE_X 0x02 /* deltas from positions array */
238 #define NEGATIVE_Y 0x04 /* ditto */
239
DoImage(Pointer ptr)240 static Error DoImage (Pointer ptr)
241 {
242 Rtaskarg *tp = (Rtaskarg *)ptr;
243
244 if (dogrid(tp) == ERROR)
245 return ERROR;
246
247 return OK;
248 }
249
250
dogrid(Rtaskarg * tp)251 static Error dogrid (Rtaskarg *tp)
252 {
253 Field field;
254 Array positions, connections;
255 Array new_positions=NULL;
256 Array new_connections=NULL;
257
258 int yfastest = 0;
259 int negative_x = 0;
260 int negative_y = 0;
261
262 int dim, counts[2], itemp;
263 int meshextents[2];
264 float origin[2], deltas[4], ftemp;
265 int otherdim;
266
267
268 field = (Field)tp->o;
269
270 /* get partition info here because i'll have to deal
271 * with fixing up the mesh offsets as well.
272 */
273 connections = (Array) DXGetComponentValue(field, "connections");
274 if (!connections) {
275 DXSetError(ERROR_MISSING_DATA, "field has no `connections' component");
276 return ERROR;
277 }
278
279 if ((!DXQueryGridConnections(connections, &dim, NULL))
280 || (dim != 2)) {
281 DXSetError(ERROR_DATA_INVALID, "connections must be a 2D regular grid");
282 goto error;
283 }
284
285 if (!DXGetMeshOffsets((MeshArray)connections, (int *)meshextents))
286 return ERROR;
287
288 /* now we have the start of this grid in meshextents and the extents
289 * of all the partitioned fields combined in tp->maxextents
290 */
291
292 #if 0
293 DXMessage("old extents: %d %d, %d %d", meshextents[0], meshextents[1],
294 tp->maxextent[0], tp->maxextent[1]);
295 #endif
296
297
298 /* verify the positions are regular and 2d
299 */
300 positions = (Array) DXGetComponentValue(field, "positions");
301 if (!positions) {
302 DXSetError(ERROR_MISSING_DATA, "field has no `positions' component");
303 return ERROR;
304 }
305
306 if ((!DXQueryGridPositions(positions, &dim, counts, origin, deltas))
307 || dim != 2) {
308 DXSetError(ERROR_DATA_INVALID, "positions must be a 2D regular grid");
309 goto error;
310 }
311
312 /* decide what to do with the grid */
313
314 /* figure out what the orientation of the input image was; we want
315 * the output deltas to be positive with x varies fastest. figure
316 * out what has to happen to the data to make that happen, and
317 * then figure out what additional thing has to happen to the
318 * data to change the orientation as the user requested.
319 */
320 if (deltas[3] != 0) {
321 yfastest++;
322 tp->grid |= Y_FASTEST;
323 tp->altergrid |= INV_EXCHANGE | INV_TRANSPOSE;
324 } else if (deltas[2] != 0) {
325 yfastest = 0;
326 } else {
327 DXSetError(ERROR_DATA_INVALID, "image must have an orthogonal grid");
328 goto error;
329 }
330
331 if (deltas[0] < 0 || deltas[2] < 0) {
332 negative_x++;
333 tp->grid |= NEGATIVE_X;
334 tp->altergrid |= INV_COLS;
335 }
336 if (deltas[1] < 0 || deltas[3] < 0) {
337 negative_y++;
338 tp->grid |= NEGATIVE_Y;
339 tp->altergrid |= INV_ROWS;
340 }
341
342 tp->count[0] = counts[0];
343 tp->count[1] = counts[1];
344
345
346 /* above this line is all setup; below this line the field is changed */
347
348
349 /* first do the data, then do the grid.
350 * this is because depending on what "how" is, this subroutine
351 * might change the "altergrid" setting.
352 */
353 if (dodata(tp) == ERROR)
354 goto error;
355
356
357 /* only do the stuff below if there is something to do */
358 if (tp->grid == 0 && tp->altergrid == 0 && tp->dotodata == 0) {
359
360 if (!DXEndField(field))
361 return ERROR;
362
363 return OK;
364 }
365
366
367 /* hack because i can't get the logic behind this right.
368 */
369 otherdim = 0;
370 /* DXMessage("grid = %d, how now = %d\n", tp->altergrid, tp->how); */
371 switch (tp->altergrid) {
372 case 0:
373 if (tp->how == 4 || tp->how == 6)
374 otherdim++;
375 break;
376 case 1:
377 if (tp->how == 1 || tp->how == 3)
378 otherdim++;
379 break;
380 case 2:
381 if (tp->how == 0 || tp->how == 2)
382 otherdim++;
383 break;
384 case 3:
385 if (tp->how == 5 || tp->how == 7)
386 otherdim++;
387 break;
388 case 4:
389 if (tp->how == 0 || tp->how == 2)
390 otherdim++;
391 break;
392 case 5:
393 if (tp->how == 5 || tp->how == 7)
394 otherdim++;
395 break;
396 case 6:
397 if (tp->how == 4 || tp->how == 6)
398 otherdim++;
399 break;
400 case 7:
401 if (tp->how == 1 || tp->how == 3)
402 otherdim++;
403 break;
404 }
405
406 /* now fix the counts and deltas to match the order the
407 * Display module is most comfortable with.
408 */
409
410 if (tp->altergrid & INV_COLS) {
411 origin[0] += deltas[0] * (counts[0]-1) + deltas[2] * (counts[1]-1);
412 if (deltas[0] != 0.0)
413 deltas[0] = -deltas[0];
414 if (deltas[2] != 0.0)
415 deltas[2] = -deltas[2];
416 }
417 if (tp->dotodata & INV_COLS) {
418 if (otherdim)
419 meshextents[1] = tp->maxextent[1] - counts[1] - meshextents[1];
420 else
421 meshextents[0] = tp->maxextent[0] - counts[0] - meshextents[0];
422 }
423 if (tp->altergrid & INV_ROWS) {
424 origin[1] += deltas[1] * (counts[0]-1) + deltas[3] * (counts[1]-1);
425 if (deltas[1] != 0.0)
426 deltas[1] = -deltas[1];
427 if (deltas[3] != 0.0)
428 deltas[3] = -deltas[3];
429 }
430 if (tp->dotodata & INV_ROWS) {
431 if (otherdim)
432 meshextents[0] = tp->maxextent[0] - counts[0] - meshextents[0];
433 else
434 meshextents[1] = tp->maxextent[1] - counts[1] - meshextents[1];
435 }
436 if (tp->altergrid & INV_TRANSPOSE) {
437 ftemp = deltas[2];
438 deltas[2] = deltas[0];
439 deltas[0] = ftemp;
440
441 ftemp = deltas[3];
442 deltas[3] = deltas[1];
443 deltas[1] = ftemp;
444 }
445 if (tp->altergrid & INV_EXCHANGE) {
446 itemp = counts[0];
447 counts[0] = counts[1];
448 counts[1] = itemp;
449 }
450 if (tp->dotodata & INV_TRANSPOSE) {
451 itemp = meshextents[0];
452 meshextents[0] = meshextents[1];
453 meshextents[1] = itemp;
454 }
455
456
457 #if 0
458 DXMessage("new extents: %d %d", meshextents[0], meshextents[1]);
459 #endif
460
461
462 /* redo the positions component */
463 new_positions = DXMakeGridPositionsV(2, counts, origin, deltas);
464 if (!new_positions)
465 goto error;
466
467 /* redo the connections component */
468 new_connections = DXMakeGridConnectionsV(2, counts);
469 if (!new_connections)
470 goto error;
471
472
473 /* and for partitioned data, fix the mesh extents */
474 if (tp->partitioned) {
475 if (!DXSetMeshOffsets((MeshArray)new_connections, (int *)meshextents))
476 return ERROR;
477 }
478
479
480 /* place in field */
481 if (!DXSetComponentValue(field, "positions", (Object)new_positions))
482 goto error;
483 if (!DXSetComponentValue(field, "connections", (Object)new_connections))
484 goto error;
485
486 if (!DXChangedComponentValues(field, "positions"))
487 goto error;
488 if (!DXChangedComponentValues(field, "connections"))
489 goto error;
490
491 if (!DXEndField(field))
492 goto error;
493
494 return OK;
495
496 error:
497 DXDelete((Object)new_positions);
498 DXDelete((Object)new_connections);
499 return ERROR;
500 }
501
502
503 #define MAXSHAPE 64
504
dodata(Rtaskarg * tp)505 static Error dodata (Rtaskarg *tp)
506 {
507 Field field;
508 Array a, new_a = NULL;
509
510 int yfastest;
511 int loopcount[2];
512 int cnum;
513 int invert;
514
515 Pointer fromptr, toptr;
516 int size;
517 ubyte *from1, *to1;
518 int *from4, *to4;
519 typedef struct {
520 ubyte _u[3];
521 } threebytes;
522 threebytes *from3, *to3;
523 typedef struct {
524 int _i[3];
525 } twelvebytes;
526 twelvebytes *from12, *to12;
527 int i, ii, j, jj, k;
528
529 char *name, *dattr, *rattr;
530 int nodeps, norefs;
531 int items;
532 Type type;
533 Category cat;
534 int rank, shape[MAXSHAPE];
535
536 int didwork;
537
538
539
540 field = (Field)tp->o;
541
542 yfastest = tp->grid & Y_FASTEST;
543 /*negative_x = tp->grid & NEGATIVE_X;*/
544 /*negative_y = tp->grid & NEGATIVE_Y;*/
545
546 #if 1 /* in again */ /*xxx out for now */
547
548 #if 0
549 DXMessage("yfastest = %d, neg_x = %d, neg_y = %d",
550 yfastest, negative_x, negative_y);
551 #endif
552
553 /* take care of all the possibilities; inverted axis and
554 * different data orientations. alter tp->how to make it match
555 * what happens with the x-fastest, positive x & y deltas.
556 */
557 if (tp->how != 0) {
558 invert = tp->grid & Y_FASTEST ? 1 : 0;
559 invert += tp->grid & NEGATIVE_X ? 1 : 0;
560 invert += tp->grid & NEGATIVE_Y ? 1 : 0;
561 switch (invert) {
562 case 2:
563 switch (tp->how) {
564 case 4:
565 tp->how = 7;
566 break;
567 case 5:
568 tp->how = 4;
569 break;
570 case 6:
571 tp->how = 5;
572 break;
573 case 7:
574 tp->how = 6;
575 break;
576 }
577 break;
578 case 1:
579 case 3:
580 switch (tp->how) {
581 case 1:
582 tp->how = 3;
583 break;
584 case 3:
585 tp->how = 1;
586 break;
587 case 5:
588 tp->how = 6;
589 break;
590 case 6:
591 tp->how = 5;
592 break;
593 case 4:
594 tp->how = 7;
595 break;
596 case 7:
597 tp->how = 4;
598 break;
599 }
600 break;
601 }
602 }
603
604 /* now that we know something about how the input image is
605 * oriented, see how the user wants it to go out.
606 */
607 switch (tp->how) {
608 case 0:
609 /* just make the image in the order the Display module
610 * is happiest handling.
611 */
612 break;
613
614 case 4:
615 tp->alterdata |= (yfastest ? INV_ROWS : INV_COLS);
616 break;
617
618 case 6:
619 tp->alterdata |= (yfastest ? INV_COLS : INV_ROWS);
620 break;
621
622 case 2:
623 tp->alterdata |= INV_ROWS;
624 tp->alterdata |= INV_COLS;
625 break;
626
627 case 7:
628 tp->altergrid ^= INV_EXCHANGE;
629 tp->alterdata |= INV_TRANSPOSE;
630 break;
631
632 case 3:
633 tp->altergrid ^= INV_EXCHANGE;
634 tp->alterdata |= INV_TRANSPOSE;
635 tp->alterdata |= (yfastest ? INV_ROWS : INV_COLS);
636 break;
637
638 case 1:
639 tp->altergrid ^= INV_EXCHANGE;
640 tp->alterdata |= INV_TRANSPOSE;
641 tp->alterdata |= (yfastest ? INV_COLS : INV_ROWS);
642 break;
643
644 case 5:
645 tp->altergrid ^= INV_EXCHANGE;
646 tp->alterdata |= INV_TRANSPOSE;
647 tp->alterdata |= INV_ROWS;
648 tp->alterdata |= INV_COLS;
649 break;
650 }
651
652
653 /* now compare what happens to the grid vs data. if we're
654 * moving the grid we can leave the data alone; if we are
655 * not moving the grid we have to move the data.
656 */
657 if ((tp->altergrid & INV_TRANSPOSE) ^ (tp->alterdata & INV_TRANSPOSE))
658 tp->dotodata |= INV_TRANSPOSE;
659 if ((tp->altergrid & INV_ROWS) ^ (tp->alterdata & INV_ROWS))
660 tp->dotodata |= INV_ROWS;
661 if ((tp->altergrid & INV_COLS) ^ (tp->alterdata & INV_COLS))
662 tp->dotodata |= INV_COLS;
663
664
665 #else
666
667
668
669 switch (tp->how) {
670 case 0:
671 /* just make the image in the order the Display module
672 * is happiest handling.
673 */
674 break;
675
676 case 4:
677 tp->alterdata |= INV_COLS;
678 break;
679
680 case 6:
681 tp->alterdata |= INV_ROWS;
682 break;
683
684 case 2:
685 tp->alterdata |= INV_ROWS | INV_COLS;
686 break;
687
688 #define FLIP(what) ((tp->altergrid & (what)) ^ (what))
689
690 case 7:
691 #if 0
692 tp->altergrid ^= INV_EXCHANGE;
693 tp->alterdata |= FLIP (INV_TRANSPOSE);
694 #endif
695 tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE;
696 break;
697
698 case 3:
699 #if 0
700 tp->altergrid ^= INV_EXCHANGE;
701 tp->alterdata |= FLIP (INV_TRANSPOSE | INV_COLS);
702 #endif
703 tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE | INV_COLS;
704 break;
705
706 case 1:
707 #if 0
708 tp->altergrid ^= INV_EXCHANGE;
709 tp->alterdata |= FLIP (INV_TRANSPOSE | INV_ROWS);
710 #endif
711 tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE | INV_ROWS;
712 break;
713
714 case 5:
715 #if 0
716 tp->altergrid ^= INV_EXCHANGE;
717 tp->alterdata |= FLIP (INV_TRANSPOSE | INV_ROWS | INV_COLS);
718 #endif
719 tp->alterdata |= INV_EXCHANGE | INV_TRANSPOSE | INV_EXCHANGE | INV_ROWS | INV_COLS;
720 break;
721 }
722
723
724 #if 0
725 DXMessage("before grid = 0x%04x, data = 0x%04x",
726 tp->altergrid, tp->alterdata);
727 #endif
728
729 #define TOGGLE(what, what1, bits) (what ^= (what1 & bits))
730
731 TOGGLE(tp->altergrid, tp->alterdata, INV_EXCHANGE);
732 tp->alterdata &= ~INV_EXCHANGE;
733 TOGGLE(tp->alterdata, tp->altergrid, INV_TRANSPOSE);
734 TOGGLE(tp->alterdata, tp->altergrid, INV_ROWS);
735 TOGGLE(tp->alterdata, tp->altergrid, INV_COLS);
736
737 #if 0
738 DXMessage("after grid = 0x%04x, data = 0x%04x",
739 tp->altergrid, tp->alterdata);
740 #endif
741
742
743 #endif
744
745 #if 0
746 DXMessage("altergrid = %d, alterdata = %d, dotodata = %d",
747 tp->altergrid, tp->alterdata, tp->dotodata);
748 #endif
749
750 /* if we don't have to change the data in the components, we're done */
751 if (tp->dotodata == INV_NOTHING)
752 return OK;
753
754
755 for (cnum = 0;
756 (a = (Array)DXGetEnumeratedComponentValue(field, cnum, &name)); cnum++) {
757
758 if (!strcmp(name, "positions") || !strcmp(name, "connections"))
759 continue;
760
761 /* if no deps and no refs, just pass this component through untouched.
762 */
763 nodeps = 0;
764 dattr = NULL;
765 if (!DXGetStringAttribute((Object)a, "dep", &dattr) || !dattr)
766 nodeps++;
767
768 norefs = 0;
769 rattr = NULL;
770 if (!DXGetStringAttribute((Object)a, "ref", &rattr) || !rattr)
771 norefs++;
772
773 if (nodeps && norefs)
774 continue;
775
776 if (dattr && strcmp(dattr, "positions") && strcmp(dattr, "connections"))
777 continue;
778
779 if (nodeps && !norefs) {
780 /* this is not dep anything but is ref something. to do this
781 * right, i need to reorder the refs the same way i reorder
782 * the target. i don't have the code to do this written, but
783 * i've got it in slab/slice and other places.
784 */
785 continue;
786 }
787
788
789 /* ok, we got a live one */
790
791 if (!strcmp(dattr, "positions")) {
792 loopcount[0] = tp->count[0];
793 loopcount[1] = tp->count[1];
794 } else {
795 loopcount[0] = tp->count[0] - 1;
796 loopcount[1] = tp->count[1] - 1;
797 }
798
799
800 size = DXGetItemSize(a);
801 fromptr = DXGetArrayData(a);
802 if (!fromptr)
803 goto error;
804
805 if (!DXGetArrayInfo(a, &items, &type, &cat, &rank, shape))
806 goto error;
807
808 new_a = DXNewArrayV(type, cat, rank, shape);
809 if (!new_a)
810 goto error;
811
812 if (!DXAddArrayData(new_a, 0, items, NULL))
813 goto error;
814
815 toptr = DXGetArrayData(new_a);
816 if (!toptr)
817 goto error;
818
819 #define MOVEDATA1(op, np) \
820 \
821 if (tp->dotodata == INV_TRANSPOSE) { \
822 for (i=0; i<loopcount[1]; i++) \
823 for (j=0; j<loopcount[0]; j++) \
824 np[i*loopcount[0] + j] = op[j*loopcount[1] + i]; \
825 } \
826 \
827 if (tp->dotodata == INV_ROWS) { \
828 for (i=0; i<loopcount[1]; i++) \
829 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
830 np[j*loopcount[1] + i] = op[jj*loopcount[1] + i]; \
831 } \
832 \
833 if (tp->dotodata == INV_COLS) { \
834 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
835 for (j=0; j<loopcount[0]; j++) \
836 np[j*loopcount[1] + i] = op[j*loopcount[1] + ii]; \
837 } \
838 \
839 if (tp->dotodata == (INV_COLS|INV_ROWS)) { \
840 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
841 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
842 np[j*loopcount[1] + i] = op[jj*loopcount[1] + ii]; \
843 } \
844 \
845 if (tp->dotodata == (INV_TRANSPOSE|INV_COLS)) { \
846 for (i=0; i<loopcount[1]; i++) \
847 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
848 np[i*loopcount[0] + j] = op[jj*loopcount[1] + i]; \
849 } \
850 \
851 if (tp->dotodata == (INV_TRANSPOSE|INV_ROWS)) { \
852 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
853 for (j=0; j<loopcount[0]; j++) \
854 np[i*loopcount[0] + j] = op[j*loopcount[1] + ii]; \
855 } \
856 \
857 if (tp->dotodata == (INV_TRANSPOSE|INV_COLS|INV_ROWS)) { \
858 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
859 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
860 np[i*loopcount[0] + j] = op[jj*loopcount[1] + ii]; \
861 }
862
863
864 #define MOVEDATA(op, np, size) \
865 \
866 if (tp->dotodata == INV_TRANSPOSE) { \
867 for (i=0; i<loopcount[1]; i++) \
868 for (j=0; j<loopcount[0]; j++) \
869 for (k=0; k<size; k++) \
870 np[(i*loopcount[0] + j)*size + k] = \
871 op[(j*loopcount[1] + i)*size + k]; \
872 } \
873 \
874 if (tp->dotodata == INV_ROWS) { \
875 for (i=0; i<loopcount[1]; i++) \
876 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
877 for (k=0; k<size; k++) \
878 np[(j*loopcount[1] + i)*size + k] = \
879 op[(jj*loopcount[1] + i)*size + k]; \
880 } \
881 \
882 if (tp->dotodata == INV_COLS) { \
883 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
884 for (j=0; j<loopcount[0]; j++) \
885 for (k=0; k<size; k++) \
886 np[(j*loopcount[1] + i)*size + k] = \
887 op[(j*loopcount[1] + ii)*size + k]; \
888 } \
889 \
890 if (tp->dotodata == (INV_COLS|INV_ROWS)) { \
891 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
892 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
893 for (k=0; k<size; k++) \
894 np[(j*loopcount[1] + i)*size + k] = \
895 op[(jj*loopcount[1] + ii)*size + k]; \
896 } \
897 \
898 if (tp->dotodata == (INV_TRANSPOSE|INV_COLS)) { \
899 for (i=0; i<loopcount[1]; i++) \
900 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
901 for (k=0; k<size; k++) \
902 np[(i*loopcount[0] + j)*size + k] = \
903 op[(jj*loopcount[1] + i)*size + k]; \
904 } \
905 \
906 if (tp->dotodata == (INV_TRANSPOSE|INV_ROWS)) { \
907 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
908 for (j=0; j<loopcount[0]; j++) \
909 for (k=0; k<size; k++) \
910 np[(i*loopcount[0] + j)*size + k] = \
911 op[(j*loopcount[1] + ii)*size + k]; \
912 } \
913 \
914 if (tp->dotodata == (INV_TRANSPOSE|INV_COLS|INV_ROWS)) { \
915 for (i=0, ii=loopcount[1]-1; i<loopcount[1]; i++, --ii) \
916 for (j=0, jj=loopcount[0]-1; j<loopcount[0]; j++, --jj) \
917 for (k=0; k<size; k++) \
918 np[(i*loopcount[0] + j)*size + k] = \
919 op[(jj*loopcount[1] + ii)*size + k]; \
920 }
921
922
923 if (size == 4) {
924 from4 = (int *)fromptr;
925 to4 = (int *)toptr;
926 MOVEDATA1(from4, to4);
927 }
928
929 else if (size == 12) {
930 from12 = (twelvebytes *)fromptr;
931 to12 = (twelvebytes *)toptr;
932 MOVEDATA1(from12, to12);
933 }
934
935 else if (size == 3) {
936 from3 = (threebytes *)fromptr;
937 to3 = (threebytes *)toptr;
938 MOVEDATA1(from3, to3);
939 }
940
941 else {
942 from1 = (ubyte *)fromptr;
943 to1 = (ubyte *)toptr;
944 MOVEDATA(from1, to1, size);
945 }
946
947
948 if (!DXSetComponentValue(field, name, (Object)new_a))
949 goto error;
950
951 new_a = NULL;
952
953 }
954
955 /* we are changing positions & connections - make sure things
956 * which are derived from them are deleted.
957 */
958 DXChangedComponentValues(field, "positions");
959 DXChangedComponentValues(field, "connections");
960
961
962
963 /* do this as a second pass so the enumeration count doesn't get mangled.
964 */
965 again:
966 didwork = 0;
967 for (i=0; (a = (Array)DXGetEnumeratedComponentValue(field, i, &name)); i++) {
968
969 if (!strcmp(name, "positions") || !strcmp(name, "connections"))
970 continue;
971
972 /* if no deps and no refs, just pass this component through untouched.
973 */
974 nodeps = 0;
975 dattr = NULL;
976 if (!DXGetStringAttribute((Object)a, "dep", &dattr) || !dattr)
977 nodeps++;
978
979 norefs = 0;
980 rattr = NULL;
981 if (!DXGetStringAttribute((Object)a, "ref", &rattr) || !rattr)
982 norefs++;
983
984 if (nodeps && norefs)
985 continue;
986
987 if (dattr && strcmp(dattr, "positions") && strcmp(dattr, "connections"))
988 continue;
989
990
991 /* the list of things which aren't going to be valid at the end
992 * after moving the positions & connections, so nuke them now rather
993 * than passing them through and having them be wrong.
994 */
995 if ((rattr && !strcmp(rattr, "positions"))
996 || (rattr && !strcmp(rattr, "connections"))) {
997 DXSetComponentValue(field, name, NULL); /* screws enum count? */
998 DXChangedComponentValues(field, name);
999 didwork++;
1000 goto again;
1001 }
1002
1003 }
1004
1005 /* done */
1006 if (!DXEndField(field))
1007 return ERROR;
1008
1009 return OK;
1010
1011 error:
1012 DXDelete((Object)new_a);
1013 return ERROR;
1014 }
1015
1016
1017
1018
1019
1020
1021