0001: /* ct_puzzle_select.c

0002:  by Arnold W., Fürth, anno Domini 2003

0003:  bcc32 -WE

0004: */
0005: 
0006: #include <windows.h>
0007: #include <stdio.h>
0008: #include <math.h>
0009: #include <dir.h>
0010: #include <sys/stat.h>
0011: #include <io.h>
0012: 
0013: typedef int GrInt;
0014: #include "ct_puzzle_common.c"
0015: #include "icontools.c"
0016: HICON IconGross = NULL, IconKlein = NULL;
0017: 
0018: #define ThisClassName "arnold's ct-Puzzle-select"
0019: #define ThisTitleBar  "Arnold's c't-Puzzle-Ergebnis-Viewing-Tool(s)"
0020: 
0021: #define ERGEBNIS  "ct_puzzle_erg.bin"
0022: #define DEFAULT_VIEWING_CMD "neut2slp -d"
0023: #define BERECHNUNGSPROGRAMM "ct_puzzle_erg"
0024: 
0025: #define MN_START_SUCHE   200
0026: #define MN_DIMETSCALE    201
0027: #define MN_DIMET_S1      202
0028: #define MN_DIMET_S2      203
0029: #define MN_DIMET_S3      204
0030: #define MN_PARTS         205
0031: #define MN_MIRROR_1      206
0032: #define MN_MIRROR_2      207
0033: #define MN_MIRROR_9      208
0034: #define MN_FILTER        209
0035: #define MN_FILTER_CLEAR  210
0036: #define MN_FILTER_A_B    211
0037: #define MN_FILTER_A_C    212
0038: #define MN_FILTER_A_D    213
0039: #define MN_INFO          290
0040: HMENU DimetrieMenu = NULL, SpiegelMenu = NULL;
0041: #define CMD_FILTER       300
0042: #define CMD_FB           316 /* letzter Wert!!! */
0043: #define CMD_FILTERINFO   301
0044: #define CMD_VWR_NAME     302
0045: #define CMD_VWR_STRT     303
0046: #define CMD_SOL_EDIT     304
0047: #define CMD_SOL_NEXT     305
0048: #define CMD_SOL_PREV     306
0049: #define CMD_ALTSUCHE     307
0050: #define CMD_SUCHE        308
0051: #define CMD_SCROLL       309
0052: #define CMD_ADDITEM      310
0053: #define CMD_ADDITEMSTRT  311
0054: #define CMD_SEARCHEND    312
0055: #define CMD_STATISTIK    313
0056: #define CMD_SEARCHPRED   314
0057: #define CMD_SEARCHSUCC   315
0058: 
0059: #define PictWidth1 60
0060: HINSTANCE hThisInstance;
0061: HWND hwndApplication;
0062: int cxChar, cyChar, cxScreen, cyScreen;
0063: int Grenze1, Grenze2, BH1, EH1, MH1, EW1, EWB1, EHD, SBx, PMx, LSx, SSx, SSy, SSl, SSp = 0, TXy;
0064: int DI1_cx, DI1_cy, DI2_cx, DI2_cy, DI_scale = 1;
0065: int Filter_an = 0, SucheAlle = 0, BitteSuchen = 0;
0066: RECT Bereich1, Bereich2, Bereich3;
0067: HWND Filter, FilterInfo;
0068: HWND Vorgaben[BAUSTEINZAHL][3];
0069: HWND Viewer_Start, Viewer_Cmd, Viewer_Title;
0070: HWND Loesung_Title, Loesung_Nr, Loesung_plus, Loesung_minus;
0071: HWND SucheAlt, SucheStart, SucheScroll, SucheStat, SuchePred, SucheSucc;
0072: HBRUSH HintergrundLeiste = NULL;
0073: int Vorgabenwerte[BAUSTEINZAHL][3][4];
0074: int VorgabeAktivBS = -1, VorgabeAktivSp = -1;
0075: int MarkierterBS = -1;
0076: 
0077: int SearchThread_halt = 0, SearchThread_halted = 1, SearchThread_start = 0, SearchThread_started = 0,
0078:     SearchThread_Suspend = 0;
0079: HANDLE SearchThread = NULL;
0080: DWORD SearchThreadId;
0081: FILE *SearchThreadDat = NULL;
0082: 
0083: unsigned long Loesung = 0; int Loesungslage = -1;
0084: int Mirror1 = 0, Mirror2 = 0, Mirror9 = 0;
0085: FILE *Loesungsdatei = NULL;
0086: unsigned short Loesungssatz[12];
0087: int LoesungssatzGueltig = 0;
0088: // MATRIX Loesungstransformationen[12];

0089: int SuchErgebnisse = 0;
0090: int SuchBlockSeite = 0;
0091: int ChoosenResult = -1;
0092: int ScrollOffset = 0;
0093: #define SuchBlockSize 1000
0094: struct SUCHBLOCK {
0095:   int in_diesem_block;
0096:   struct SUCHBLOCK *next, *prev;
0097:   unsigned long Ergebnis[SuchBlockSize];
0098: } *StartSuchBlock = NULL, *AktiverSuchBlock = NULL, *LetzterSuchBlock = NULL;
0099: 
0100: char *ErgebnisString(int EintragNummer)
0101: { int block, index;
0102:   static char ErgString[40];
0103:   block = EintragNummer / SuchBlockSize;
0104:   index = EintragNummer % SuchBlockSize;
0105:   ErgString[0] = '\0';
0106:   if (StartSuchBlock == NULL) return ErgString;
0107:   if (block == 0) {
0108:     AktiverSuchBlock = StartSuchBlock; SuchBlockSeite = 0;
0109:   } else
0110:   if (block != SuchBlockSeite) {
0111:     if (block > SuchBlockSeite) {
0112:       while ((block != SuchBlockSeite) && (AktiverSuchBlock->next != NULL)) {
0113:         AktiverSuchBlock = AktiverSuchBlock->next; SuchBlockSeite++;
0114:       }
0115:     } else { /* block < SuchBlcokSeite */
0116:       while ((block != SuchBlockSeite) && (AktiverSuchBlock->prev != NULL)) {
0117:         AktiverSuchBlock = AktiverSuchBlock->prev; SuchBlockSeite--;
0118:       }
0119:     }
0120:   }
0121:   if (AktiverSuchBlock->in_diesem_block > index) {
0122:     if ((AktiverSuchBlock->Ergebnis[index] >> 28) & 4)
0123:       sprintf(ErgString, "%lu", AktiverSuchBlock->Ergebnis[index] & 0x0fffffffL);
0124:      else
0125:       sprintf(ErgString, "%lu%c", AktiverSuchBlock->Ergebnis[index] & 0x0fffffffL,
0126:          'a' + (((AktiverSuchBlock->Ergebnis[index]) >> 28) & 3));
0127:   }
0128:   return ErgString;
0129: }
0130: 
0131: void PredSuccEnable(void)
0132: { EnableWindow(SuchePred, SuchErgebnisse ? TRUE : FALSE);
0133:   EnableWindow(SucheSucc, SuchErgebnisse ? TRUE : FALSE);
0134: }
0135: 
0136: void ClearErgebnis(void)
0137: { struct SUCHBLOCK *sb;
0138:   SuchErgebnisse = SuchBlockSeite = SSp = 0;
0139:   PredSuccEnable();
0140:   AktiverSuchBlock = LetzterSuchBlock = StartSuchBlock;
0141:   for (sb = StartSuchBlock; sb != NULL; sb = sb->next) sb->in_diesem_block = 0;
0142:   ChoosenResult = -1;
0143:   SetWindowText(SucheStat, "");
0144: }
0145: 
0146: void AddErgebnis(unsigned long Nummer, int Lage)
0147: { unsigned long Schreibwert;
0148:   struct SUCHBLOCK *Satz, *neu;
0149:   char Zwischenstatistik[50];
0150:   Schreibwert = Nummer | (Lage << 28);
0151:   if (StartSuchBlock == NULL) {
0152:     if((Satz = malloc(sizeof(struct SUCHBLOCK))) == NULL) return;
0153:     Satz->next = NULL; Satz->prev = NULL; Satz->in_diesem_block = 0;
0154:     StartSuchBlock = Satz;
0155:     AktiverSuchBlock = Satz;
0156:     LetzterSuchBlock = Satz;
0157:     SuchBlockSeite = 0;
0158:   }
0159:   Satz = LetzterSuchBlock;
0160:   while (Satz->in_diesem_block >= SuchBlockSize) {
0161:     if (Satz->next == NULL) {
0162:       if ((neu = malloc(sizeof(struct SUCHBLOCK))) == NULL) return;
0163:       neu->prev = Satz; neu->next = NULL; neu->in_diesem_block = 0;
0164:       LetzterSuchBlock = neu;
0165:       Satz->next = neu;
0166:       Satz = neu;
0167:     } else Satz = Satz->next;
0168:   }
0169:   Satz->Ergebnis[Satz->in_diesem_block] = Schreibwert;
0170:   (Satz->in_diesem_block)++;
0171:   SuchErgebnisse++;
0172:   PredSuccEnable();
0173:   sprintf(Zwischenstatistik, "%u/%lu", SuchErgebnisse, Nummer & 0x0fffffffL);
0174:   SetWindowText(SucheStat, Zwischenstatistik);
0175: }
0176: 
0177: void StartLoesungsBerechnung(int start_von_winmain)
0178: { int ok;
0179:   STARTUPINFO si;
0180:   static PROCESS_INFORMATION pi;
0181:   static calculation_started = 0;
0182:   DWORD ec;
0183:   if (!start_von_winmain) {
0184:     if (!access(ERGEBNIS, 4)) {
0185:       if (MessageBox(hwndApplication,
0186:         "Sie wollen die Lösungstabelle neu berechnen lassen, obwohl die Datei \""
0187:         ERGEBNIS "\" bereits vorhanden ist?\n"
0188:         "Da diese Berechnung einige Stunden dauern kann (gemessen auf meinem Testrechner),"
0189:         " überlegen Sie es sich gut, ob sie dies jetzt tun wollen, denn Sie sollten den"
0190:         " Berechnungslauf nicht vorzeitig abbrechen.\n"
0191:         "\nWollen Sie nun die Lösungstabelle neu berechnen?",
0192:         "c't-Puzzle-Lösungstabelle berechnen", MB_ICONQUESTION | MB_OKCANCEL | MB_DEFBUTTON2) == IDCANCEL)
0193:         return;
0194:     }
0195:   }
0196:   do {
0197:     ok = 1;
0198:     /* Läuft Suche ? */
0199:     if (!SearchThread_halted || (SearchThreadDat != NULL)) {
0200:       if (MessageBox(hwndApplication, "Um die Lösungsssuche starten zu können,"
0201:         " muß die Filtersuche erst abgeschlossen sein!",
0202:         "Lösungssuche starten ...", MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDCANCEL) return;
0203:       ok = 0;
0204:     }
0205:     /* Schon gestartet und noch nicht beendet? */
0206:     if (calculation_started) {
0207:       if (GetExitCodeProcess(pi.hProcess, &ec)) {
0208:         if (ec != STILL_ACTIVE) calculation_started = 0;
0209:       }
0210:     }
0211:     if (calculation_started) {
0212:       if (MessageBox(hwndApplication, "Es wurde bereits eine Lösungssuche gestartet und diese ist noch"
0213:         "nicht beendet.\n", "Lösungssuche starten ...",
0214:         MB_ICONEXCLAMATION | MB_RETRYCANCEL | MB_DEFBUTTON2) == IDCANCEL) return;
0215:       ok = 0;
0216:     }
0217:   } while (!ok);
0218:   if (Loesungsdatei != NULL) fclose(Loesungsdatei);
0219:   memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO);
0220:   if (CreateProcess(NULL, BERECHNUNGSPROGRAMM, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
0221:                 NULL, NULL, &si, &pi)) {
0222:     calculation_started = 1;
0223:     MessageBox(hwndApplication, "Die Berechnung der Lösungstabelle wurde gestartet. "
0224:       "Dies kann einige Zeit dauern, bitte haben Sie deshalb jetzt etwas Geduld:\n"
0225:       "Auf meinem Testrechner benötigte dieser Rechenlauf\n"
0226:       "\n ca. 3\xbd Stunden Rechenzeit.\n\n[in Worten: sieben mal dreißig Minuten]",
0227:       "Berechnung gestartet", MB_ICONINFORMATION | MB_OK | MB_SYSTEMMODAL);
0228:   } else {
0229:     MessageBox(hwndApplication, "Das Berechnungsprogramm \"" BERECHNUNGSPROGRAMM "\" konnte nicht gestartet"
0230:       " werden!", "Fehler beim Starten der Lösungssuche", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
0231:   }
0232: }
0233: 
0234: int SuchtGerade(void)
0235: { char Z[20];
0236:   GetWindowText(SucheStart, Z, 20);
0237:   Z[19] = '\0';
0238:   if (!strcmp(Z, "Suche ...")) return 1;
0239:   return 0;
0240: }
0241: 
0242: void AdjustScrollbarSize(void)
0243: { SCROLLINFO si;
0244:   si.cbSize = sizeof(si);
0245:   si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
0246:   si.nPos = ScrollOffset;
0247:   si.nPage = SSl; si.nMin = 0; si.nMax = SuchErgebnisse - 1;
0248:   SetScrollInfo(SucheScroll, SB_CTL, &si, TRUE);
0249: }
0250: 
0251: int BausteinNummer(unsigned short InsertID)
0252: { return(((InsertID >> 12) & 15) - 1); }
0253: 
0254: MATRIX Orientierung(unsigned short InsertID)
0255: { MATRIX erg;
0256:   int xdir, ydir;
0257:   memset(&erg, 0, sizeof(MATRIX));
0258:   /* Richtung X-Achse des Bausteinkoordinatensystems */
0259:   xdir = (InsertID >> 10) & 3;
0260:   erg.MATRIX[xdir] = ((InsertID >> 9) & 1) ? -1 : 1;
0261:   /* Richtung Y-Achse des Bausteinkoordinatensystems */
0262:   ydir = (xdir + 1 + ((InsertID >> 8) & 1)) % 3 + 3;
0263:   erg.MATRIX[ydir] = ((InsertID >> 7) & 1) ? -1 : 1;
0264:   /* Kreuzprodukt für Z-Achse */
0265:   erg.MATRIX[8] = erg.MATRIX[0] * erg.MATRIX[4] - erg.MATRIX[1] * erg.MATRIX[3];
0266:   erg.MATRIX[6] = erg.MATRIX[1] * erg.MATRIX[5] - erg.MATRIX[2] * erg.MATRIX[4];
0267:   erg.MATRIX[7] = erg.MATRIX[2] * erg.MATRIX[3] - erg.MATRIX[0] * erg.MATRIX[5];
0268:   /* Ursprung */
0269:   erg.MATRIX[ 9] = (InsertID >>  4) & 7;
0270:   erg.MATRIX[10] = (InsertID >> 2) & 3;
0271:   erg.MATRIX[11] =  InsertID & 3;
0272:   /* Ergebnisrückgabe */
0273:   return erg;
0274: }
0275: 
0276: #include "ct_puzzle_gdata.c"
0277: 
0278: 
0279: void ViewerStartLoesung(void)
0280: { int ct, bs, a, i;
0281:   MATRIX m;
0282:   STARTUPINFO si;
0283:   PROCESS_INFORMATION pi;
0284:   FILE *posdat;
0285:   char PosDat[MAX_PATH];
0286:   char Programm[2 * MAXPATH];
0287:   if (!LoesungssatzGueltig) return;
0288:   a = Loesungslage; if (a < 0) a = 0;
0289:   mkdir("loesungen");
0290:   sprintf(PosDat, "loesungen\\ct_puzzle_%.6lu%c.pos", Loesung, 'a' + a);
0291:   if ((posdat = fopen(PosDat, "w")) == NULL) {
0292:     char M[MAX_PATH + 70];
0293:     sprintf(M, "Datei '%s' konnte nicht angelegt werden!", PosDat);
0294:     MessageBox(NULL, M, "Datenübergabe fehlgeschlagen", MB_ICONEXCLAMATION | MB_OK);
0295:     return;
0296:   }
0297:   for (ct = 0; ct < BAUSTEINZAHL; ct++) {
0298:     bs = BausteinNummer(Loesungssatz[ct]);
0299:     if ((bs >= 0) && (bs < BAUSTEINZAHL)) {
0300:       if ((bs == 0) && Mirror1) {
0301:         m = MatMul(Hinlegen[a], MatMul(Orientierung(Loesungssatz[ct]), INV1));
0302:       } else
0303:       if ((bs == 1) && Mirror2) {
0304:         m = MatMul(Hinlegen[a], MatMul(Orientierung(Loesungssatz[ct]), INV2));
0305:       } else
0306:       if ((bs == 8) && Mirror9) {
0307:         m = MatMul(Hinlegen[a], MatMul(Orientierung(Loesungssatz[ct]), INV9));
0308:       } else
0309:         m = MatMul(Hinlegen[a], Orientierung(Loesungssatz[ct]));
0310:       fprintf(posdat, "%2d  ", bs + 1);
0311:       for (i = 0; i < 12; i++) fprintf(posdat, " %2d", m.MATRIX[i]);
0312:       fprintf(posdat, "\n");
0313:     }
0314:   }
0315:   fclose(posdat);
0316:   GetWindowText(Viewer_Cmd, Programm, MAX_PATH);
0317:   Programm[MAX_PATH - 1] = '\0';
0318:   strcat(Programm, " ");
0319:   strcat(Programm, PosDat);
0320:   // system(Programm);

0321:   memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO);
0322:   CreateProcess(NULL, Programm, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
0323:                 NULL, NULL, &si, &pi);
0324: }
0325: 
0326: void CheckCheckbox(HWND hwnd, int set_it)
0327: { SendMessage(hwnd, BM_SETCHECK, set_it ? BST_CHECKED : BST_UNCHECKED, 0L); }
0328: 
0329: void SetSwitches(void)
0330: { int b, i;
0331:   CheckCheckbox(Filter, Filter_an);
0332:   for (b = 0; b < BAUSTEINZAHL; b++) for (i = 0; i < 3; i++)
0333:     EnableWindow(Vorgaben[b][i], Filter_an ? TRUE : FALSE);
0334:   EnableWindow(SucheAlt, Filter_an ? TRUE : FALSE);
0335:   EnableWindow(SucheStart, Filter_an ? TRUE : FALSE);
0336:   EnableWindow(SucheScroll, Filter_an ? TRUE : FALSE);
0337:   CheckCheckbox(SucheAlt, SucheAlle);
0338: }
0339: 
0340: void CreateSubwindows(HWND hwnd)
0341: { int b, i;
0342:   /* 1. Sektion */
0343:   Filter = CreateWindow("button", "Lösungen filtern",
0344:     WS_CHILD | WS_VISIBLE | BS_CHECKBOX | WS_BORDER,
0345:     0, 0, 0, 0, hwnd, (HMENU) CMD_FILTER, hThisInstance, NULL);
0346:   for (b = 0; b < BAUSTEINZAHL; b++) for (i = 0; i < 3; i++) {
0347:     Vorgaben[b][i] = CreateWindow("edit", "", WS_CHILD | WS_VISIBLE | WS_BORDER,
0348:       0, 0, 0, 0, hwnd, (HMENU) (CMD_FB + 3 * b + i), hThisInstance, NULL);
0349:     Vorgabenwerte[b][i][3] = 0;
0350:   }
0351:   FilterInfo = CreateWindow("static", "",
0352:     WS_CHILD | WS_VISIBLE | SS_LEFT,
0353:     0, 0, 0, 0, hwnd, (HMENU) CMD_FILTERINFO, hThisInstance, NULL);
0354:   /* 2. Sektion */
0355:   SucheAlt = CreateWindow("button", "mit Rotationen",
0356:     WS_CHILD | WS_VISIBLE | BS_CHECKBOX | WS_BORDER,
0357:     0, 0, 0, 0, hwnd, (HMENU) CMD_ALTSUCHE, hThisInstance, NULL);
0358:   SucheStart  = CreateWindow("button", BitteSuchen ? "Suchen!" : "Suchen",
0359:     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0360:     0, 0, 0, 0, hwnd, (HMENU) CMD_SUCHE, hThisInstance, NULL);
0361:   SucheScroll  = CreateWindow("scrollbar", NULL,
0362:     WS_CHILD | WS_VISIBLE | SBS_VERT,
0363:     0, 0, 0, 0, hwnd, (HMENU) CMD_SCROLL, hThisInstance, NULL);
0364:   SucheStat = CreateWindow("static", "",
0365:     WS_CHILD | WS_VISIBLE | SS_CENTER,
0366:     0, 0, 0, 0, hwnd, (HMENU) CMD_STATISTIK, hThisInstance, NULL);
0367:   SucheSucc  = CreateWindow("button", "+",
0368:     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0369:     0, 0, 0, 0, hwnd, (HMENU) CMD_SEARCHSUCC, hThisInstance, NULL);
0370:   SuchePred  = CreateWindow("button", "-",
0371:     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0372:     0, 0, 0, 0, hwnd, (HMENU) CMD_SEARCHPRED, hThisInstance, NULL);
0373:   /* 3. Sektion */
0374:   Viewer_Title = CreateWindow("static", "3D-Viewer:",
0375:     WS_CHILD | WS_VISIBLE | SS_LEFT,
0376:     0, 0, 0, 0, hwnd, (HMENU) 0, hThisInstance, NULL);
0377:   Viewer_Cmd = CreateWindow("edit", DEFAULT_VIEWING_CMD,
0378:     WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
0379:     0, 0, 0, 0, hwnd, (HMENU) CMD_VWR_NAME, hThisInstance, NULL);
0380:   Viewer_Start = CreateWindow("button", "START",
0381:     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0382:     0, 0, 0, 0, hwnd, (HMENU) CMD_VWR_STRT, hThisInstance, NULL);
0383:   Loesung_Title = CreateWindow("static", "Lösung Nr.:",
0384:     WS_CHILD | WS_VISIBLE | SS_LEFT | WS_BORDER,
0385:     0, 0, 0, 0, hwnd, (HMENU) 0, hThisInstance, NULL);
0386:   Loesung_Nr = CreateWindow("edit", "",
0387:     WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | ES_LOWERCASE,
0388:     0, 0, 0, 0, hwnd, (HMENU) CMD_SOL_EDIT, hThisInstance, NULL);
0389:   Loesung_plus  = CreateWindow("button", "+",
0390:     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0391:     0, 0, 0, 0, hwnd, (HMENU) CMD_SOL_NEXT, hThisInstance, NULL);
0392:   Loesung_minus = CreateWindow("button", "-",
0393:     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0394:     0, 0, 0, 0, hwnd, (HMENU) CMD_SOL_PREV, hThisInstance, NULL);
0395:   SetSwitches();
0396: }
0397: 
0398: void CheckSolutionNumber(int aktion)
0399: { char Nummer[22], NummerNeu[22];
0400:   int md, p, q, nr, alternative; char c;
0401:   struct stat sb;
0402:   DWORD sel_strt, sel_end;
0403:   GetWindowText(Loesung_Nr, Nummer, 22); Nummer[21] = '\0';
0404:   SendMessage(Loesung_Nr, EM_GETSEL, (WPARAM) (LPDWORD) &sel_strt, (LPARAM) (LPDWORD) &sel_end);
0405:   nr = 0; c = ' ';
0406:   md = 0; NummerNeu[0] = '\0';
0407:   for (p = q = 0; Nummer[p]; p++) {
0408:     switch (md) {
0409:       case 0:
0410:         if ((Nummer[p] >= '0') && (Nummer[p] <= '9')) {
0411:           NummerNeu[q] = Nummer[p];
0412:           NummerNeu[++q] = '\0';
0413:         } else if (q) {
0414:           switch (Nummer[p]) {
0415:             case 'a': case 'A': NummerNeu[q++] = 'a'; md = 1; break;
0416:             case 'b': case 'B': NummerNeu[q++] = 'b'; md = 1; break;
0417:             case 'c': case 'C': NummerNeu[q++] = 'c'; md = 1; break;
0418:             case 'd': case 'D': NummerNeu[q++] = 'd'; md = 1; break;
0419:           }
0420:           NummerNeu[q] = '\0';
0421:         } else {
0422:           if (sel_strt) sel_strt--;
0423:           if (sel_end) sel_end--;
0424:         }
0425:       break;
0426:     }
0427:   }
0428:   NummerNeu[20] = '\0';
0429:   if (sel_strt > strlen(NummerNeu)) sel_strt = strlen(NummerNeu);
0430:   if (sel_end > strlen(NummerNeu)) sel_end = strlen(NummerNeu);
0431:   sscanf(NummerNeu, "%u%c", &nr, &c);
0432:   switch (c) {
0433:     case 'a': case 'A': alternative = 0; break;
0434:     case 'b': case 'B': alternative = 1; break;
0435:     case 'c': case 'C': alternative = 2; break;
0436:     case 'd': case 'D': alternative = 3; break;
0437:     default: alternative = -1;
0438:   }
0439:   if (!aktion) {
0440:     if (!stat(ERGEBNIS, &sb)) {
0441:       if (nr > sb.st_size / 24L) nr = sb.st_size / 24L;
0442:       if (alternative >= 0) sprintf(NummerNeu, "%u%c", nr, 'a' + alternative);
0443:                        else sprintf(NummerNeu, "%u", nr);
0444:       ChoosenResult = -1;
0445:     }
0446:     if (strcmp(Nummer, NummerNeu)) {
0447:       SetWindowText(Loesung_Nr, NummerNeu);
0448:       SendMessage(Loesung_Nr, EM_SETSEL, (WPARAM) (INT) sel_strt, (LPARAM) (INT) sel_end);
0449:     }
0450:   }
0451:   if (aktion) {
0452:     if ((nr > 1) || (aktion > 0)) nr += aktion;
0453:     if (!stat(ERGEBNIS, &sb)) {
0454:       if (nr > sb.st_size / 24L) nr = sb.st_size / 24L;
0455:     }
0456:     if (nr == 0) nr = 1;
0457:     if (alternative >= 0) sprintf(Nummer, "%c", 'a' + alternative); else Nummer[0] = '\0';
0458:     sprintf(NummerNeu, "%u%s", nr, Nummer);
0459:     NummerNeu[20] = '\0';
0460:     SetWindowText(Loesung_Nr, NummerNeu);
0461:     ChoosenResult = -1;
0462:   }
0463: }
0464: 
0465: void SelectSolutionNumber(HWND hwnd)
0466: { char Nummer[22];
0467:   int nr, alternative; char c;
0468:   GetWindowText(Loesung_Nr, Nummer, 22); Nummer[21] = '\0';
0469:   nr = 0; c = ' ';
0470:   sscanf(Nummer, "%u%c", &nr, &c);
0471:   switch (c) {
0472:     case 'a': case 'A': alternative = 0; break;
0473:     case 'b': case 'B': alternative = 1; break;
0474:     case 'c': case 'C': alternative = 2; break;
0475:     case 'd': case 'D': alternative = 3; break;
0476:     default: alternative = -1;
0477:   }
0478:   if (nr > 0) {
0479:     Loesung = nr, Loesungslage = alternative;
0480:     if (Loesungsdatei == NULL) {
0481:       if ((Loesungsdatei = fopen(ERGEBNIS, "rb")) == NULL) {
0482:         LoesungssatzGueltig = 0; return;
0483:       }
0484:     }
0485:     fseek(Loesungsdatei, 24L * (Loesung - 1), SEEK_SET);
0486:     fread(Loesungssatz, 24, 1, Loesungsdatei);
0487:     LoesungssatzGueltig = 1;
0488:     InvalidateRect(hwnd, &Bereich3, TRUE);
0489:   } else 
0490:   if (LoesungssatzGueltig) {
0491:     LoesungssatzGueltig = 0;
0492:     InvalidateRect(hwnd, &Bereich3, TRUE);
0493:   }
0494: }
0495: 
0496: void SetDimetScale(int scale)
0497: { DI_scale = scale;
0498:   CheckMenuItem(DimetrieMenu, MN_DIMET_S1, MF_BYCOMMAND | ((DI_scale == 1) ? MF_CHECKED : MF_UNCHECKED));
0499:   CheckMenuItem(DimetrieMenu, MN_DIMET_S2, MF_BYCOMMAND | ((DI_scale == 2) ? MF_CHECKED : MF_UNCHECKED));
0500:   CheckMenuItem(DimetrieMenu, MN_DIMET_S3, MF_BYCOMMAND | ((DI_scale == 3) ? MF_CHECKED : MF_UNCHECKED));
0501:   DI1_cx = (cxScreen + Grenze2 + 93 * DI_scale) / 2;
0502:   DI2_cx = (cxScreen + Grenze2 - 93 * DI_scale) / 2;
0503:   DI1_cy = (1 * (cyScreen - 3 * BH1 - 1) - 114 * DI_scale) / 4 + BH1 + 1;
0504:   DI2_cy = (3 * (cyScreen - 3 * BH1 - 1) - 114 * DI_scale) / 4 + BH1 + 1;
0505: }
0506: 
0507: #pragma argsused
0508: void ChangeSize(HWND hwnd, LPARAM lParam)
0509: { int b, i;
0510:   HDC hdc;
0511:   TEXTMETRIC tm;
0512:   /* Schriften */
0513:   hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc);
0514:   TXy = tm.tmHeight + tm.tmExternalLeading + 2;
0515:   /* allgemein bzw. Bereich 1 */
0516:   EW1 = 6 * cxChar;
0517:   Grenze1 = 3 * EW1 + PictWidth1;
0518:   Grenze2 = Grenze1 + 15 * cxChar;
0519:   Bereich1.top = 0; Bereich1.left = 0; Bereich1.bottom = cyScreen; Bereich1.right = Grenze1;
0520:   Bereich2.top = 0; Bereich2.left = Grenze1; Bereich2.bottom = cyScreen; Bereich2.right = Grenze2;
0521:   Bereich3.top = 0; Bereich3.left = Grenze2; Bereich3.bottom = cyScreen; Bereich3.right = cxScreen;
0522:   BH1 = cyChar + 6;
0523:   EHD = EH1 = (cyScreen - BH1 - 2) / (BAUSTEINZAHL + 2);
0524:   MH1 = cyScreen - BH1 - BAUSTEINZAHL * EH1 - 1;
0525:   EWB1 = BH1 + EH1 / 2 + 1;
0526:   if (EH1 > cyChar + 6) { EH1 = cyChar + 6; }
0527:   /* Bereich 2 */
0528:   SSx = Grenze2 - 2 * cxChar;
0529:   SSy = 2 * BH1 + 1;
0530:   SSl = (cyScreen - SSy - 2 * BH1) / TXy;
0531:   /* Bereich 3 */
0532:   SBx = cxScreen - 7 * cxChar; if (SBx <= Grenze2) SBx = Grenze2 + 1;
0533:   LSx = 9 * cxChar;
0534:   PMx = cxScreen - 2 * cxChar; if (PMx <= Grenze2) { PMx = Grenze2 + 1; LSx = 0; }
0535:   SetDimetScale(DI_scale); /* nur, damit der Ursprung neu berechnet wird */
0536:   /* Bereich 1 */
0537:   MoveWindow(Filter, 1, 1, Grenze1 - 1, BH1, TRUE);
0538:   for (b = 0; b < BAUSTEINZAHL; b++)
0539:    for (i = 0; i < 3; i++)
0540:     MoveWindow(Vorgaben[b][i], Grenze1 - (3 - i) * EW1 + 1, EWB1 - EH1 / 2 + b * EHD , EW1 - 2, EH1 - 2, TRUE);
0541:   MoveWindow(FilterInfo, 0, cyScreen - MH1, Grenze1, MH1, TRUE);
0542:   /* Bereich 2 */
0543:   MoveWindow(SucheAlt,   Grenze1 + 1,       1, Grenze2 - Grenze1 - 1, BH1, TRUE);
0544:   MoveWindow(SucheStart, Grenze1 + 1, BH1 + 1, Grenze2 - Grenze1 - 1, BH1, TRUE);
0545:   MoveWindow(SucheStat,  Grenze1 + 1, cyScreen - BH1, Grenze2 - Grenze1 - 1, BH1, TRUE);
0546:   MoveWindow(SuchePred,  Grenze1 + 1, cyScreen - 2 * BH1, (Grenze2 - Grenze1 - 1) / 2, BH1, TRUE);
0547:   MoveWindow(SucheSucc,  Grenze2 - (Grenze2 - Grenze1 - 1) / 2, cyScreen - 2 * BH1,
0548:                          (Grenze2 - Grenze1 - 1) / 2, BH1, TRUE);
0549:   MoveWindow(SucheScroll, SSx, SSy, 2 * cxChar, cyScreen - SSy - 2 * BH1, TRUE);
0550:   PredSuccEnable();
0551:   /* Bereich 3 */
0552:   MoveWindow(Loesung_plus, PMx, 1, cxScreen - PMx, BH1 / 2, TRUE);
0553:   MoveWindow(Loesung_minus, PMx, BH1 / 2 + 1, cxScreen - PMx, BH1 / 2, TRUE);
0554:   MoveWindow(Loesung_Title, Grenze2 + 1, 1, PMx - Grenze2 - 1, BH1, TRUE);
0555:   MoveWindow(Loesung_Nr, PMx - LSx - 1, 2, LSx, BH1 - 2, TRUE);
0556:   MoveWindow(Viewer_Title, Grenze2 + 1, cyScreen - 2 * BH1, SBx - Grenze2 - 1, BH1, TRUE);
0557:   MoveWindow(Viewer_Cmd, Grenze2 + 1, cyScreen - BH1, SBx - Grenze2 - 1, BH1, TRUE);
0558:   MoveWindow(Viewer_Start, SBx, cyScreen - 2 * BH1, cxScreen - SBx, 2 * BH1, TRUE);
0559: }
0560: 
0561: void FilterLoeschen(void)
0562: { int bs, i;
0563:   for (bs = 0; bs < BAUSTEINZAHL; bs++) for (i = 0; i < 3; i++) {
0564:     SetWindowText(Vorgaben[bs][i], "");
0565:     Vorgabenwerte[bs][i][3] = 0;
0566:   }
0567: }
0568: 
0569: void FilterWenden(int a)
0570: { KOORD k;
0571:   int bs, i;
0572:   char Position[16];
0573:   for (bs = 0; bs < BAUSTEINZAHL; bs++) for (i = 0; i < 3; i++) if (Vorgabenwerte[bs][i][3]) {
0574:     k = PosTrans3i(Hinlegen[a], Vorgabenwerte[bs][i][0], Vorgabenwerte[bs][i][1], Vorgabenwerte[bs][i][2]);
0575:     Vorgabenwerte[bs][i][0] = k.KOORD[0];
0576:     Vorgabenwerte[bs][i][1] = k.KOORD[1];
0577:     Vorgabenwerte[bs][i][2] = k.KOORD[2];
0578:     sprintf(Position, "%d,%d,%d", k.KOORD[0], k.KOORD[1], k.KOORD[2]);
0579:     SetWindowText(Vorgaben[bs][i], Position);
0580:   }
0581:   BitteSuchen = 1;
0582:   if (!SuchtGerade()) SetWindowText(SucheStart, "Suchen!");
0583: }
0584: 
0585: #pragma argsused
0586: DWORD WINAPI SearchThreadProc(LPVOID dummy)
0587: { unsigned short Erg[12];
0588:   unsigned long p;
0589:   int a, ct, bs, i, verwerfen, halten, bed;
0590:   BAUSTEIN BS;
0591:   char Endstatistik[50];
0592:   SearchThreadDat = NULL;
0593:   while (1) {
0594:     if (SearchThread_halt) {
0595:       if (SearchThreadDat != NULL) fclose(SearchThreadDat); SearchThreadDat = NULL;
0596:       if (!SearchThread_halted) {
0597:         SearchThread_halted = 1;
0598:         SendMessage(hwndApplication, WM_COMMAND, CMD_SEARCHEND, 0L);
0599:       }
0600:       SwitchToThread();
0601:       Sleep(350);
0602:     } else {
0603:       if (SearchThread_start) {
0604:         SearchThread_started = 1;
0605:         SearchThread_start = SearchThread_halted = 0;
0606:         SendMessage(hwndApplication, WM_COMMAND, CMD_ADDITEMSTRT, 0L);
0607:         p = 0;
0608:         if ((SearchThreadDat = fopen(ERGEBNIS, "rb")) == NULL) {
0609:           SearchThread_halt = 1;
0610:         } else {
0611:           BitteSuchen = 0;
0612:           SetWindowText(SucheStart, "Suche ...");
0613:         }
0614:       } else {
0615:         if (fread(Erg, 24, 1, SearchThreadDat) > 0) {
0616:           p++;
0617:           for (a = 0; a < (SucheAlle ? 4 : 1); a++) {
0618:             halten = 1;
0619:             for (ct = 0; (ct < BAUSTEINZAHL) && halten; ct++) {
0620:               bs = BausteinNummer(Erg[ct]);
0621:               if ((bs >= 0) && (bs < BAUSTEINZAHL)) {
0622:                 BS = BewegterBaustein(Baustein[bs], MatMul(Hinlegen[a], Orientierung(Erg[ct])));
0623:                 for (bed = 0; bed < 3; bed++) if (Vorgabenwerte[bs][bed][3]) {
0624:                   verwerfen = 1;
0625:                   for (i = 0; i < BS.Teilwuerfelzahl; i++) {
0626:                     if ((BS.Einzelelemente[i].KOORD[0] == Vorgabenwerte[bs][bed][0])
0627:                      && (BS.Einzelelemente[i].KOORD[1] == Vorgabenwerte[bs][bed][1])
0628:                      && (BS.Einzelelemente[i].KOORD[2] == Vorgabenwerte[bs][bed][2])) verwerfen = 0;
0629:                   }
0630:                   if (verwerfen) halten = 0;
0631:                 }
0632:               }
0633:             }
0634:             if (halten) {
0635:               SendMessage(hwndApplication, WM_COMMAND, CMD_ADDITEM, p | (SucheAlle ? (a << 28) : 0x40000000L));
0636:             }
0637:           }
0638:         } else {
0639:           fclose(SearchThreadDat); SearchThreadDat = NULL;
0640:           SearchThread_halt = 1;
0641:           SetWindowText(SucheStart, BitteSuchen ? "Suchen!" : "Suchen");
0642:           InvalidateRect(hwndApplication, &Bereich2, TRUE);
0643:           sprintf(Endstatistik, "%u/%lu", SuchErgebnisse, p);
0644:           SetWindowText(SucheStat, Endstatistik);
0645:         }
0646:       }
0647:     }
0648:   }
0649: }
0650: 
0651: void StarteSuche(HWND hwnd)
0652: { int ct, bs, i;
0653:   ct = 0;
0654:   for (bs = 0; bs < BAUSTEINZAHL; bs++) for (i = 0; i < 3; i++) ct += Vorgabenwerte[bs][i][3];
0655:   if (!ct) {
0656:     MessageBox(hwnd, "Es ist unsinnig eine Filtersuche zu starten, ohne eine Bauteilbeschränkung"
0657:                      " eingegeben zu haben.\n\n"
0658:                      "Suche nicht gestartet!", "Kein Grund zur Filtersuche", MB_ICONEXCLAMATION | MB_OK);
0659:     return;
0660:   }
0661:   SearchThread_started = 0;
0662:   SearchThread_start = 1;
0663:   SearchThread_halt = 0;
0664:   if (SearchThread == NULL) {
0665:     SearchThread = CreateThread(NULL, 0, SearchThreadProc, NULL, 0, &SearchThreadId);
0666:   }
0667:   do {
0668:     ResumeThread(SearchThread);
0669:     SearchThread_Suspend--;
0670:   } while (SearchThread_Suspend > 0);
0671:   if (SearchThread_Suspend < 0) SearchThread_Suspend = 0;
0672: }
0673: 
0674: #pragma argsused
0675: void ScrollAction(HWND hwnd, int Notification, int Cmd, LPARAM lParam)
0676: { SCROLLINFO si;
0677:   switch(Cmd) {
0678:     case SB_LINEUP:
0679:       if (--ScrollOffset < 0) ScrollOffset = 0;
0680:     break;
0681:     case SB_LINEDOWN:
0682:       ScrollOffset++;
0683:       if (ScrollOffset + SSl > SuchErgebnisse) ScrollOffset = SuchErgebnisse - SSl;
0684:       if (ScrollOffset < 0) ScrollOffset = 0;
0685:     break;
0686:     case SB_PAGEUP:
0687:       ScrollOffset -= SSl;
0688:       if (--ScrollOffset < 0) ScrollOffset = 0;
0689:     break;
0690:     case SB_PAGEDOWN:
0691:       ScrollOffset += SSl;
0692:       if (ScrollOffset + SSl > SuchErgebnisse) ScrollOffset = SuchErgebnisse - SSl;
0693:       if (ScrollOffset < 0) ScrollOffset = 0;
0694:     break;
0695:     case SB_THUMBTRACK:
0696:     case SB_THUMBPOSITION:
0697:       si.cbSize = sizeof(si);
0698:       si.fMask = SIF_ALL;
0699:       GetScrollInfo(SucheScroll, SB_CTL, &si);
0700:       ScrollOffset = si.nTrackPos;
0701:       if (ScrollOffset + SSl > SuchErgebnisse) ScrollOffset = SuchErgebnisse - SSl;
0702:       if (ScrollOffset < 0) ScrollOffset = 0;
0703:       if (Cmd == SB_THUMBTRACK) InvalidateRect(hwnd, &Bereich2, TRUE);
0704:     break;
0705:   }
0706:   si.cbSize = sizeof(si);
0707:   si.fMask = SIF_POS;
0708:   si.nPos = ScrollOffset;
0709:   SetScrollInfo(SucheScroll, SB_CTL, &si, TRUE);
0710:   InvalidateRect(hwnd, &Bereich2, TRUE);
0711: }
0712: 
0713: void NextScrollErg(HWND hwnd, int inc)
0714: { SCROLLINFO si;
0715:   int neupos;
0716:   if (!SuchErgebnisse) return;
0717:   if (ChoosenResult < 0) {
0718:     if (inc > 0) neupos = 0; else neupos = SuchErgebnisse - 1;
0719:   } else {
0720:     if (ChoosenResult + inc >= SuchErgebnisse) return;
0721:     if (ChoosenResult + inc < 0) return;
0722:     neupos = ChoosenResult + inc;
0723:   }
0724:   if (ScrollOffset > neupos) {
0725:     ScrollOffset = neupos;
0726:     si.cbSize = sizeof(si);
0727:     si.fMask = SIF_POS;
0728:     si.nPos = ScrollOffset;
0729:     SetScrollInfo(SucheScroll, SB_CTL, &si, TRUE);
0730:   } else
0731:   if (neupos >= ScrollOffset + SSl) {
0732:     ScrollOffset = neupos - SSl + 1;
0733:     if (ScrollOffset < 0) ScrollOffset = 0;
0734:     si.cbSize = sizeof(si);
0735:     si.fMask = SIF_POS;
0736:     si.nPos = ScrollOffset;
0737:     SetScrollInfo(SucheScroll, SB_CTL, &si, TRUE);
0738:   }
0739:   SetWindowText(Loesung_Nr, ErgebnisString(neupos));
0740:   ChoosenResult = neupos;
0741:   InvalidateRect(hwnd, &Bereich2, TRUE);
0742: }
0743: 
0744: void ZeigeHinweise(HWND hwnd)
0745: { MessageBox(hwnd,
0746:     "Allgemeine Hinweise zu diesem Programm:\n\n"
0747: 
0748:     "- Wenn Sie eine bestimmte Lösungsnummer sehen wollen, so geben Sie die Nummer in dem Eingabefeld"
0749:     " rechts oben ein. Hängen Sie noch einen Buchstaben (a bis d) an, wenn Sie auch die Gesamtorientierung"
0750:     " ändern wollen.\n"
0751: 
0752:     "- Wollen Sie wissen, wieviele Lösungen überhaupt in der Lösungsdatei gespeichert sind, dann geben Sie einfach"
0753:     " eine sehr hohe Zahl ein, sie wird automatisch herabgesetzt.\n"
0754: 
0755:     "- Filtervorgaben (Raumkoordinaten, an denen ein bestimmtes Puzzleteil liegen soll) können Sie auch bequem"
0756:     " durch einen Mausklick (linke Taste) auf den entsprechenden Teilwürfel in der dimetrischen Darstellung"
0757:     " in das Eingabefeld übernehmen.\n"
0758:     "- Wenn Sie statt dessen wissen wollen, welches Puzzleteil an einer Position der angezeigten Lösung liegt,"
0759:     " dann klicken Sie diesen Teilwürfel mit der rechten Maustaste an.\n"
0760: 
0761:     "- Änderungen der Filtereinstellung wirken sich sofort auf die laufende Filtersuche aus. Wenn Sie also die"
0762:     " Filtereinstellungen ändern während die Filtersuche noch läuft, genügen die ersten Suchergebnisse anderen"
0763:     " Bedingungen als die letzten Suchergebnisse.\n"
0764:     "- Sie können sich die Lösung auch räumlich rotierbar ansehen. Der Aufruf des mitgelieferten Standardviewers"
0765:     " (Anweisung \"neut2slp -d\") kann im Eingabefeld rechts unten ersetzt werden, um andere mit der Übergabesyntax"
0766:     " kompatible Anzeigeprogramme zu starten.\n"
0767:     "Nachdem Sie im mitgelieferten Standardviewer die Spachumstellung gefunden haben, werden Sie sicher auch unter"
0768:     " \"Objektdarstellung\" die Möglichkeit finden, die Einzelteile des Puzzles einzeln aus- und wieder einzublenden.\n"
0769:     "Die Übergabe der Platzierungpositionen der einzelen Bausteine für diesen Standardviewer steht in einer Datei"
0770:     " mit der Endung \".pos\" im Unterverzeichnis \"loesungen\". Es empfiehlt sich, den Inhalt dieses"
0771:     " Temporärverzeichnisses gelegentlich wieder zu löschen.\n"
0772: 
0773:     "\nSollten bei der Berechung der Lösungstabelle in dem Textfenster statt Umlauten seltsame Zeichen erscheinen,"
0774:     " liegt das womöglich an der Zeichensatzeinstellung des 'DOS-Fensters': Rasterfont statt UNICODE-True-Type-Font.\n"
0775:     "\n\xa9 Arnold Wendl, Fürth, anno Domini 2003\n\n"
0776:     "P.S. Mein Testrechner war ein Pentium MMX mit 233 MHz, 192 MB RAM und Shared Memory Grafik.",
0777:     ThisTitleBar " - Info", MB_ICONINFORMATION | MB_OK);
0778: }
0779: 
0780: void CommandAction(HWND hwnd, int Notification, int Cmd, LPARAM lParam)
0781: { switch (Cmd) {
0782:     case CMD_SUCHE:
0783:       StarteSuche(hwnd);
0784:     break;
0785:     case CMD_SEARCHEND:
0786:       SuspendThread(SearchThread);
0787:       SearchThread_Suspend++;
0788:     break;
0789:     case CMD_SEARCHPRED:
0790:       NextScrollErg(hwnd, -1);
0791:     break;
0792:     case CMD_SEARCHSUCC:
0793:       NextScrollErg(hwnd, 1);
0794:     break;
0795:     case CMD_ADDITEMSTRT:
0796:       ClearErgebnis();
0797:       ScrollOffset = 0;
0798:       AdjustScrollbarSize();
0799:     break;
0800:     case CMD_ADDITEM:
0801:       /* if (vorherige Suche ist beendet) */
0802:       AddErgebnis((unsigned long) lParam, 0);
0803:       AdjustScrollbarSize();
0804:       if (ScrollOffset + SSl >= SuchErgebnisse) InvalidateRect(hwnd, &Bereich2, TRUE);
0805:     break;
0806:     case CMD_FILTER:
0807:       Filter_an = !Filter_an;
0808:       SetSwitches();
0809:     break;
0810:     case CMD_ALTSUCHE:
0811:       SucheAlle = !SucheAlle;
0812:       BitteSuchen = 1;
0813:       SetSwitches();
0814:     break;
0815:     case CMD_VWR_STRT:
0816:       ViewerStartLoesung();
0817:     break;
0818:     case MN_START_SUCHE:
0819:       StartLoesungsBerechnung(0);
0820:     break;
0821:     case MN_FILTER_CLEAR:
0822:       FilterLoeschen();
0823:     break;
0824:     case MN_FILTER_A_B:
0825:     case MN_FILTER_A_C:
0826:     case MN_FILTER_A_D:
0827:       FilterWenden(Cmd - MN_FILTER_CLEAR);
0828:     break;
0829:     case MN_INFO:
0830:       ZeigeHinweise(hwnd);
0831:     break;
0832:     case MN_DIMET_S1:
0833:       SetDimetScale(1);
0834:       InvalidateRect(hwnd, &Bereich3, TRUE);
0835:     break;
0836:     case MN_DIMET_S2:
0837:       SetDimetScale(2);
0838:       InvalidateRect(hwnd, &Bereich3, TRUE);
0839:     break;
0840:     case MN_DIMET_S3:
0841:       SetDimetScale(3);
0842:       InvalidateRect(hwnd, &Bereich3, TRUE);
0843:     break;
0844:     case MN_MIRROR_1:
0845:       Mirror1 = !Mirror1;
0846:       CheckMenuItem(SpiegelMenu, MN_MIRROR_1, MF_BYCOMMAND | (Mirror1 ? MF_CHECKED : MF_UNCHECKED));
0847:       InvalidateRect(hwnd, &Bereich1, TRUE);
0848:       InvalidateRect(hwnd, &Bereich3, TRUE);
0849:     break;
0850:     case MN_MIRROR_2:
0851:       Mirror2 = !Mirror2;
0852:       CheckMenuItem(SpiegelMenu, MN_MIRROR_2, MF_BYCOMMAND | (Mirror2 ? MF_CHECKED : MF_UNCHECKED));
0853:       InvalidateRect(hwnd, &Bereich1, TRUE);
0854:       InvalidateRect(hwnd, &Bereich3, TRUE);
0855:     break;
0856:     case MN_MIRROR_9:
0857:       Mirror9 = !Mirror9;
0858:       CheckMenuItem(SpiegelMenu, MN_MIRROR_9, MF_BYCOMMAND | (Mirror9 ? MF_CHECKED : MF_UNCHECKED));
0859:       InvalidateRect(hwnd, &Bereich1, TRUE);
0860:       InvalidateRect(hwnd, &Bereich3, TRUE);
0861:     break;
0862:     case CMD_SOL_NEXT:
0863:       CheckSolutionNumber(1);
0864:       SelectSolutionNumber(hwnd);
0865:       ChoosenResult = -1;
0866:       InvalidateRect(hwnd, &Bereich2, TRUE);
0867:     break;
0868:     case CMD_SOL_PREV:
0869:       CheckSolutionNumber(-1);
0870:       SelectSolutionNumber(hwnd);
0871:       ChoosenResult = -1;
0872:       InvalidateRect(hwnd, &Bereich2, TRUE);
0873:     break;
0874:     case CMD_SOL_EDIT:
0875:       switch (Notification) {
0876:         case EN_UPDATE:
0877:           CheckSolutionNumber(0);
0878:         break;
0879:         case EN_CHANGE:
0880:           CheckSolutionNumber(0);
0881:           SelectSolutionNumber(hwnd);
0882:           ChoosenResult = -1;
0883:           InvalidateRect(hwnd, &Bereich2, TRUE);
0884:         break;
0885:         case EN_KILLFOCUS:
0886:           // ReadSolutionNumber();

0887:         break;
0888:       }
0889:     break;
0890:     default:
0891:       if ((Cmd >= CMD_FB) && (Cmd - CMD_FB < 3 * BAUSTEINZAHL)) {
0892:         int bs, i, x, y, z;
0893:         char Box[40];
0894:         switch (Notification) {
0895:           /* case EN_UPDATE:    T = "EN_UPDATE"; break; */
0896:           case EN_CHANGE:
0897:             bs = (Cmd - CMD_FB) / 3;
0898:             i = (Cmd - CMD_FB) % 3;
0899:             x = y = z = -1;
0900:             GetWindowText(Vorgaben[bs][i], Box, 39); Box[39] = '\0';
0901:             sscanf(Box, "%d,%d,%d", &x, &y, &z);
0902:             if ((x < 0) || (y < 0) || (z < 0)) {
0903:               Vorgabenwerte[bs][i][3] = 0;
0904:               SetWindowText(FilterInfo, "Koordinate ist (noch) ungültig. Bitte Form \"x,y,z\" einhalten.");
0905:             } else
0906:             if (x > 4) {
0907:               Vorgabenwerte[bs][i][3] = 0;
0908:               SetWindowText(FilterInfo, "Koordinate ist ungültig. Bitte x-Wert zwischen 0 und 4 einhalten.");
0909:             } else
0910:             if (y > 3) {
0911:               Vorgabenwerte[bs][i][3] = 0;
0912:               SetWindowText(FilterInfo, "Koordinate ist ungültig. Bitte y-Wert zwischen 0 und 3 einhalten.");
0913:             } else
0914:             if (z > 2) {
0915:               Vorgabenwerte[bs][i][3] = 0;
0916:               SetWindowText(FilterInfo, "Koordinate ist ungültig. Bitte z-Wert zwischen 0 und 2 einhalten.");
0917:             } else {
0918:               Vorgabenwerte[bs][i][0] = x; Vorgabenwerte[bs][i][1] = y; Vorgabenwerte[bs][i][2] = z;
0919:               Vorgabenwerte[bs][i][3] = 1;
0920:               SetWindowText(FilterInfo, "");
0921:             }
0922:             BitteSuchen = 1;
0923:             if (!SuchtGerade()) SetWindowText(SucheStart, "Suchen!");
0924:           break;
0925:           case EN_KILLFOCUS:
0926:             VorgabeAktivBS = VorgabeAktivSp = -1;
0927:             SetWindowText(FilterInfo, "");
0928:           break;
0929:           case EN_SETFOCUS:
0930:             VorgabeAktivBS = (Cmd - CMD_FB) / 3;
0931:             VorgabeAktivSp = (Cmd - CMD_FB) % 3;
0932:             SetWindowText(FilterInfo, "Bitte Koordinaten in der Form \"x,y,z\" angeben. "
0933:               "Oder wählen Sie rechts im Raumbild eine Position aus.");
0934:           break;
0935:         }
0936:       }
0937:   }
0938: }
0939: 
0940: void Text(HDC hdc, char *Text, UINT Alignment)
0941: { POINT akt_pos;
0942:   UINT TextAlign;
0943:   int PrevBKM;
0944:   GetCurrentPositionEx(hdc, &akt_pos);
0945:   TextAlign = GetTextAlign(hdc);
0946:   SetBkMode(hdc, TRANSPARENT);
0947:   if (Alignment) SetTextAlign(hdc, Alignment);
0948:   TextOut(hdc, akt_pos.x, akt_pos.y, Text, strlen(Text));
0949:   SetTextAlign(hdc, TextAlign);
0950:   SetBkMode(hdc, PrevBKM);
0951: }
0952: 
0953: void Pfeil(HDC hdc, float Richtung, float Spitzwinkel, float Schenkellaenge)
0954: { POINT akt_pos[3];
0955:   GetCurrentPositionEx(hdc, akt_pos);
0956:   akt_pos[1].x = akt_pos[0].x
0957:     + floor(Schenkellaenge * cos(M_PI * (180.0 + Richtung + 0.5 * Spitzwinkel) / 180.0) + 0.5);
0958:   akt_pos[1].y = akt_pos[0].y
0959:     - floor(Schenkellaenge * sin(M_PI * (180.0 + Richtung + 0.5 * Spitzwinkel) / 180.0) + 0.5);
0960:   akt_pos[2].x = akt_pos[0].x
0961:     + floor(Schenkellaenge * cos(M_PI * (180.0 + Richtung - 0.5 * Spitzwinkel) / 180.0) + 0.5);
0962:   akt_pos[2].y = akt_pos[0].y
0963:     - floor(Schenkellaenge * sin(M_PI * (180.0 + Richtung - 0.5 * Spitzwinkel) / 180.0) + 0.5);
0964:   BeginPath(hdc); Polyline(hdc, akt_pos, 3); EndPath(hdc); StrokeAndFillPath(hdc);
0965: }
0966: 
0967: void MoveTo3D(HDC hdc, int Ansicht, int x, int y, int z, int teiler)
0968: { int px, py;
0969:   if (Ansicht > 0) {
0970:     px = DI1_cx - (5 * 24 - 3 * 9) * DI_scale;
0971:     py = DI1_cy - (5 * 3 + 3 * 8 - 4 * 24) * DI_scale;
0972:     px += (24 * x - 9 * z) * DI_scale / teiler;
0973:     py += (3 * x - 24 * y + 8 * z) * DI_scale / teiler;
0974:   } else {
0975:     px = DI2_cx; py = DI2_cy;
0976:     px += (24 * x - 9 * z) * DI_scale / teiler;
0977:     py += (24 * y - 3 * x - 8 * z) * DI_scale / teiler;
0978:   }
0979:   MoveToEx(hdc, px, py, NULL);
0980: }
0981: 
0982: void LineTo3D(HDC hdc, int Ansicht, int x, int y, int z, int teiler)
0983: { int px, py;
0984:   if (Ansicht > 0) {
0985:     px = DI1_cx - (5 * 24 - 3 * 9) * DI_scale;
0986:     py = DI1_cy - (5 * 3 + 3 * 8 - 4 * 24) * DI_scale;
0987:     px += (24 * x - 9 * z) * DI_scale / teiler;
0988:     py += (3 * x - 24 * y + 8 * z) * DI_scale / teiler;
0989:   } else {
0990:     px = DI2_cx; py = DI2_cy;
0991:     px += (24 * x - 9 * z) * DI_scale / teiler;
0992:     py += (24 * y - 3 * x - 8 * z) * DI_scale / teiler;
0993:   }
0994:   LineTo(hdc, px, py);
0995: }
0996: 
0997: void SurfaceLine3D(HDC hdc, int Ansicht, KOORD p1, KOORD p2)
0998: { if ((Ansicht >= 0)
0999:    && (((p1.KOORD[0] == 45) && (p2.KOORD[0] == 45))
1000:     || ((p1.KOORD[1] == 35) && (p2.KOORD[1] == 35))
1001:     || ((p1.KOORD[2] == 25) && (p2.KOORD[2] == 25)))) {
1002:     MoveTo3D(hdc, 1, p1.KOORD[0] + 5, p1.KOORD[1] + 5, p1.KOORD[2] + 5, 10);
1003:     LineTo3D(hdc, 1, p2.KOORD[0] + 5, p2.KOORD[1] + 5, p2.KOORD[2] + 5, 10);
1004:   }
1005:   if ((Ansicht <= 0)
1006:    && (((p1.KOORD[0] == -5) && (p2.KOORD[0] == -5))
1007:     || ((p1.KOORD[1] == -5) && (p2.KOORD[1] == -5))
1008:     || ((p1.KOORD[2] == -5) && (p2.KOORD[2] == -5)))) {
1009:     MoveTo3D(hdc, -1, p1.KOORD[0] + 5, p1.KOORD[1] + 5, p1.KOORD[2] + 5, 10);
1010:     LineTo3D(hdc, -1, p2.KOORD[0] + 5, p2.KOORD[1] + 5, p2.KOORD[2] + 5, 10);
1011:   }
1012: }
1013: 
1014: void BausteinSurfaceLines3D(HDC hdc, int Ansicht, MATRIX m, int *surfaces)
1015: { int p; MATRIX M;
1016:   if (surfaces == NULL) return;
1017:   if (surfaces[0] >= 9999) return;
1018:   /* "explodieren", da die Oberflächen in zehntel-Einheiten beschrieben sind */
1019:   M = m; for (p = 9; p < 12; p++) M.MATRIX[p] *= 10;
1020:   for (p = 0; surfaces[p + 3] < 9999;) {
1021:     if (surfaces[p + 3] == 2000) { /* Move */
1022:       p += 4;
1023:     } else { /* Draw */
1024:       SurfaceLine3D(hdc, Ansicht,
1025:                     PosTrans3i(M, surfaces[p    ], surfaces[p + 1], surfaces[p + 2]),
1026:                     PosTrans3i(M, surfaces[p + 3], surfaces[p + 4], surfaces[p + 5]));
1027:       p += 3;
1028:     }
1029:   }
1030: }
1031: 
1032: void PaintLoesung(HDC hdc, int Ansicht)
1033: { HPEN Stift, altStift;
1034:   int ct, bs, a, i;
1035:   MATRIX m;
1036:   if (!LoesungssatzGueltig) return;
1037:   a = Loesungslage; if (a < 0) a = 0;
1038:   altStift = GetCurrentObject(hdc, OBJ_PEN);
1039:   Stift = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
1040:   SelectObject(hdc, Stift);
1041:   for (ct = 0; ct < BAUSTEINZAHL; ct++) {
1042:     bs = BausteinNummer(Loesungssatz[ct]);
1043:     if ((bs >= 0) && (bs < BAUSTEINZAHL)) {
1044:       if ((bs == 0) && Mirror1) {
1045:         m = MatMul(Hinlegen[a], MatMul(Orientierung(Loesungssatz[ct]), INV1));
1046:       } else
1047:       if ((bs == 1) && Mirror2) {
1048:         m = MatMul(Hinlegen[a], MatMul(Orientierung(Loesungssatz[ct]), INV2));
1049:       } else
1050:       if ((bs == 8) && Mirror9) {
1051:         m = MatMul(Hinlegen[a], MatMul(Orientierung(Loesungssatz[ct]), INV9));
1052:       } else
1053:         m = MatMul(Hinlegen[a], Orientierung(Loesungssatz[ct]));
1054:       BausteinSurfaceLines3D(hdc, Ansicht, m, SURFACELINES[bs]);
1055:     }
1056:   }
1057:   SelectObject(hdc, altStift);
1058:   DeleteObject(Stift);
1059: }
1060: 
1061: void PaintSection3(HDC hdc)
1062: { HPEN Stift1, Stift2, alterStift;
1063:   HBRUSH Farbe1, Farbe2, Farbe3, Farbe4, alteFarbe;
1064:   POINT R1[4], R2[4], R3[4];
1065:   int c, x, y, Ansicht;
1066:   alteFarbe = GetCurrentObject(hdc, OBJ_BRUSH);
1067:   alterStift = GetCurrentObject(hdc, OBJ_PEN);
1068:   Farbe1 = CreateSolidBrush(RGB(224, 224, 255)); /* rechts */
1069:   Farbe2 = CreateSolidBrush(RGB(255, 255, 255)); /* oben */
1070:   Farbe3 = CreateSolidBrush(RGB(255, 255, 224)); /* links */
1071:   Farbe4 = CreateSolidBrush(RGB(255,   0,   0)); /* links */
1072:   Stift1 = CreatePen(PS_SOLID, 0, RGB(0, 0, 255));
1073:   Stift2 = CreatePen(PS_SOLID, 0, RGB(0, 255, 255));
1074:   
1075:   BeginPath(hdc); Rectangle(hdc, Grenze2 + 1, 1, cxScreen, cyScreen); EndPath(hdc);
1076:   SelectClipPath(hdc, RGN_COPY);
1077: #define DI_cx(a) ((a > 0) ? DI1_cx : DI2_cx)
1078: #define DI_cy(a) ((a > 0) ? DI1_cy : DI2_cy)
1079:   SelectObject(hdc, Farbe4);
1080:   for (Ansicht = -1; Ansicht < 2; Ansicht += 2) {
1081:     MoveTo3D(hdc, Ansicht, 0, 0, 0, 1); LineTo3D(hdc, Ansicht, 50 * DI_scale + 10, 0, 0, 10 * DI_scale);
1082:     Text(hdc, " x", TA_BASELINE | TA_LEFT);
1083:     Pfeil(hdc,   -7.125  * Ansicht, 22.0, 15.0);
1084:     MoveTo3D(hdc, Ansicht, 0, 0, 0, 1); LineTo3D(hdc, Ansicht, 0, 40 * DI_scale + 10, 0, 10 * DI_scale);
1085:     Text(hdc, "y", ((Ansicht > 0) ? TA_BOTTOM : TA_TOP) | TA_CENTER);
1086:     Pfeil(hdc,   90.0    * Ansicht, 22.0, 15.0);
1087:     MoveTo3D(hdc, Ansicht, 0, 0, 0, 1); LineTo3D(hdc, Ansicht, 0, 0, 30 * DI_scale + 15, 10 * DI_scale);
1088:     Text(hdc, "z", ((Ansicht > 0) ? TA_TOP : TA_BOTTOM) | TA_RIGHT);
1089:     Pfeil(hdc, -138.3665 * Ansicht, 22.0, 15.0);
1090:   }
1091:   for (Ansicht = -1; Ansicht < 2; Ansicht += 2) {
1092:     /* -1 : untere Ansicht, +1 : obere Ansicht */
1093:     R1[0].x = DI_cx(Ansicht);                           R1[0].y = DI_cy(Ansicht);
1094:     R1[1].x = DI_cx(Ansicht);                           R1[1].y = DI_cy(Ansicht) + 96 * DI_scale;
1095:     R1[2].x = DI_cx(Ansicht) + 27 * DI_scale * Ansicht; R1[2].y = DI_cy(Ansicht) + 72 * DI_scale;
1096:     R1[3].x = DI_cx(Ansicht) + 27 * DI_scale * Ansicht; R1[3].y = DI_cy(Ansicht) - 24 * DI_scale;
1097:     R2[0].x = DI_cx(Ansicht);                           R2[0].y = DI_cy(Ansicht);
1098:     R2[1].x = DI_cx(Ansicht) + 27 * DI_scale * Ansicht; R2[1].y = DI_cy(Ansicht) - 24 * DI_scale;
1099:     R2[2].x = DI_cx(Ansicht) - 93 * DI_scale * Ansicht; R2[2].y = DI_cy(Ansicht) - 39 * DI_scale;
1100:     R2[3].x = DI_cx(Ansicht) -120 * DI_scale * Ansicht; R2[3].y = DI_cy(Ansicht) - 15 * DI_scale;
1101:     R3[0].x = DI_cx(Ansicht);                           R3[0].y = DI_cy(Ansicht);
1102:     R3[1].x = DI_cx(Ansicht) -120 * DI_scale * Ansicht; R3[1].y = DI_cy(Ansicht) - 15 * DI_scale;
1103:     R3[2].x = DI_cx(Ansicht) -120 * DI_scale * Ansicht; R3[2].y = DI_cy(Ansicht) + 81 * DI_scale;
1104:     R3[3].x = DI_cx(Ansicht);                           R3[3].y = DI_cy(Ansicht) + 96 * DI_scale;
1105:     SelectObject(hdc, Stift2);
1106:     SelectObject(hdc, (Ansicht > 0) ? Farbe1 : Farbe3);
1107:     BeginPath(hdc); Polyline(hdc, R1, 4); EndPath(hdc); FillPath(hdc);
1108:     SelectObject(hdc, Farbe2);
1109:     BeginPath(hdc); Polyline(hdc, R2, 4); EndPath(hdc); FillPath(hdc);
1110:     SelectObject(hdc, (Ansicht > 0) ? Farbe3 : Farbe1);
1111:     BeginPath(hdc); Polyline(hdc, R3, 4); EndPath(hdc); FillPath(hdc);
1112:     for (c = 1; c < 3; c++) {
1113:       MoveToEx(hdc, DI_cx(Ansicht) +  9 * c        * DI_scale * Ansicht,
1114:                     DI_cy(Ansicht) + (96 - 8 * c)  * DI_scale, NULL);
1115:       LineTo  (hdc, DI_cx(Ansicht) +  9 * c        * DI_scale * Ansicht,
1116:                     DI_cy(Ansicht) -       8 * c   * DI_scale);
1117:       LineTo  (hdc, DI_cx(Ansicht) + (9 * c - 120) * DI_scale * Ansicht,
1118:                     DI_cy(Ansicht) - (15 + 8 * c)  * DI_scale);
1119:     }
1120:     for (c = 1; c < 4; c++) {
1121:       MoveToEx(hdc, DI_cx(Ansicht) -  120           * DI_scale * Ansicht,
1122:                     DI_cy(Ansicht) + ( 24 * c - 15) * DI_scale, NULL);
1123:       LineTo  (hdc, DI_cx(Ansicht)                                      ,
1124:                     DI_cy(Ansicht) +   24 * c       * DI_scale);
1125:       LineTo  (hdc, DI_cx(Ansicht) +   27           * DI_scale * Ansicht,
1126:                     DI_cy(Ansicht) + ( 24 * c - 24) * DI_scale);
1127:     }
1128:     for (c = 1; c < 5; c++) {
1129:       MoveToEx(hdc, DI_cx(Ansicht) -       24 * c  * DI_scale * Ansicht,
1130:                     DI_cy(Ansicht) + (96 -  3 * c) * DI_scale, NULL);
1131:       LineTo  (hdc, DI_cx(Ansicht) -       24 * c  * DI_scale * Ansicht,
1132:                     DI_cy(Ansicht) -        3 * c  * DI_scale);
1133:       LineTo  (hdc, DI_cx(Ansicht) + (27 - 24 * c) * DI_scale * Ansicht,
1134:                     DI_cy(Ansicht) - (24 +  3 * c) * DI_scale);
1135:     }
1136:     SelectObject(hdc, Stift1);
1137:     BeginPath(hdc); Polyline(hdc, R1, 4); EndPath(hdc); StrokePath(hdc);
1138:     BeginPath(hdc); Polyline(hdc, R2, 4); EndPath(hdc); StrokePath(hdc);
1139:     BeginPath(hdc); Polyline(hdc, R3, 4); EndPath(hdc); StrokePath(hdc);
1140:     PaintLoesung(hdc, Ansicht);
1141:   }
1142:   /* Abschluss */
1143:   SelectObject(hdc, alteFarbe);
1144:   SelectObject(hdc, alterStift);
1145: #ifdef Ursprungskreuz
1146:   MoveToEx(hdc, DI1_cx - 10, DI1_cy - 10, NULL);
1147:   LineTo(hdc, DI1_cx + 10, DI1_cy + 10);
1148:   MoveToEx(hdc, DI1_cx + 10, DI1_cy - 10, NULL);
1149:   LineTo(hdc, DI1_cx - 10, DI1_cy + 10);
1150:   MoveToEx(hdc, DI2_cx - 10, DI2_cy - 10, NULL);
1151:   LineTo(hdc, DI2_cx + 10, DI2_cy + 10);
1152:   MoveToEx(hdc, DI2_cx + 10, DI2_cy - 10, NULL);
1153:   LineTo(hdc, DI2_cx - 10, DI2_cy + 10);
1154: #endif

1155:   DeleteObject(Farbe1); DeleteObject(Farbe2); DeleteObject(Farbe3); DeleteObject(Farbe4);
1156:   DeleteObject(Stift1); DeleteObject(Stift2);
1157: }
1158: 
1159: void PaintIsoBS(HDC hdc, RECT *rect, int *data, int xS, int yS)
1160: { int xmin, xmax, ymin, ymax, extset = 0, p, i;
1161:   POINT P[BS_ISO_MAX_POINTS];
1162:   HBRUSH falt, F[3];
1163:   if (hdc != NULL) {
1164:     falt = GetCurrentObject(hdc, OBJ_BRUSH);
1165:     F[0] = CreateSolidBrush(RGB(255, 255, 255));
1166:     F[1] = CreateSolidBrush(RGB(255, 255,   0));
1167:     F[2] = CreateSolidBrush(RGB(  0, 255, 255));
1168:   }  
1169:   for (p = 0; data[p] < 9999;) {
1170:     if (data[p] >= 1000) { /* Farbe */
1171:       if (data[p] < 1003) SelectObject(hdc, F[data[p] - 1000]);
1172:       p++; i = 0;
1173:     } else {
1174:       if (extset) {
1175:         if (xmin > xS + data[p]) xmin = xS +data[p]; else if (xmax < xS + data[p]) xmax = xS + data[p];
1176:         if (ymin > yS - data[p+1]) ymin = yS - data[p+1]; else if (ymax < yS - data[p+1]) ymax = yS -data[p+1];
1177:       } else { xmin = xmax = data[p]; ymin = ymax = yS - data[p + 1]; extset = 1; }
1178:       if (hdc != NULL) { P[i].x = xS + data[p]; P[i].y = yS - data[p+1]; i++; }
1179:       p += 2;
1180:     }
1181:     if ((hdc != NULL) && (data[p] >= 1000)) {
1182:       BeginPath(hdc);
1183:       Polyline(hdc, P, i);
1184:       EndPath(hdc);
1185:       StrokeAndFillPath(hdc);
1186:       i = 0;
1187:     }
1188:   }
1189:   if (rect != NULL) {
1190:     rect->top = ymin; rect->bottom = ymax; rect->left = xmin; rect->right = xmax;
1191:   }
1192:   if (hdc != NULL) {
1193:     SelectObject(hdc, falt);
1194:     for (i = 0; i < 3; i++) DeleteObject(F[i]);
1195:   }
1196: }
1197: 
1198: void PaintSection2(HDC hdc)
1199: { int y, ct, bkm, crf;
1200:   RECT r;
1201:   r.left = Grenze1 + 1; r.right = SSx;
1202:   bkm = SetBkMode(hdc, TRANSPARENT);
1203:   for (ct = 0; ct < SSl; ct++) {
1204:     r.top = SSy + ct * TXy;
1205:     r.bottom = r.top + TXy;
1206:     if (ct + ScrollOffset == ChoosenResult) crf = SetTextColor(hdc, RGB(255, 0, 0));
1207:     DrawText(hdc, ErgebnisString(ct + ScrollOffset), -1, &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
1208:     if (ct + ScrollOffset == ChoosenResult) SetTextColor(hdc, crf);
1209:   }
1210:   SetBkMode(hdc, bkm);
1211: }
1212: 
1213: void PaintSection1(HDC hdc)
1214: { int y, b; RECT r;
1215:   char RectInfo[300];
1216:   HPEN altstift, stift;
1217:   COLORREF bkcolor;
1218:   altstift = GetCurrentObject(hdc, OBJ_PEN);
1219:   bkcolor = GetBkColor(hdc);
1220:   stift = CreatePen(PS_DOT, 0, RGB(0, 0, 0)); /* Zur Wahl: DOT, DASHDOT */
1221:   SetBkColor(hdc, RGB(255, 255, 128));
1222:   y = EWB1;
1223:   for (b = 0; b < BAUSTEINZAHL; b++) {
1224:     if (b == MarkierterBS) {
1225:       MoveToEx(hdc, 0, y - EHD / 2, NULL);
1226:       LineTo(hdc, PictWidth1, y - EHD / 2);
1227:       LineTo(hdc, PictWidth1, y + EHD / 2);
1228:       LineTo(hdc, 0 , y + EHD / 2);
1229:       LineTo(hdc, 0 , y - EHD / 2);
1230:     }
1231:     if (((b == 0) && Mirror1) || ((b == 1) && Mirror2) || ((b == 8) && Mirror9)) {
1232:       SelectObject(hdc, stift);
1233:       MoveToEx(hdc, PictWidth1 / 2 + 4 * EHD / 7, y - EHD / 2, NULL);
1234:       LineTo(  hdc, PictWidth1 / 2 - 4 * EHD / 7, y + EHD / 2);
1235:       SelectObject(hdc, altstift);
1236:     }
1237:     PaintIsoBS(NULL, &r, BS_ISO[b], 0, 0);
1238:     PaintIsoBS(hdc, NULL, BS_ISO[b], (PictWidth1 - r.right + r.left) / 2, y + (r.bottom - r.top) / 2);
1239:     sprintf(RectInfo, "{ l=%d, r=%d, t=%d, b=%d } -> %d, %d\n",
1240:       r.left, r.right, r.top, r.bottom, (PictWidth1 - r.right + r.left) / 2, y + (r.bottom - r.top) / 2);
1241:     y += EHD;
1242:   }
1243:   SetBkColor(hdc, bkcolor);
1244:   DeleteObject(stift);
1245: }
1246: 
1247: void PaintGlobal(HDC hdc)
1248: { HPEN stift1, stift2, altstift;
1249:   altstift = GetCurrentObject(hdc, OBJ_PEN);
1250:   stift1 = CreatePen(PS_SOLID, 0, RGB(255, 255, 255));
1251:   stift2 = CreatePen(PS_SOLID, 0, RGB(  0,   0, 128));
1252:   SelectObject(hdc, stift2);
1253:   MoveToEx(hdc, Grenze1, 0, NULL); LineTo(hdc, Grenze1, cyScreen);
1254:   MoveToEx(hdc, Grenze2, 0, NULL); LineTo(hdc, Grenze2, cyScreen);
1255:   SelectObject(hdc, stift1);
1256:   MoveToEx(hdc, 0, 0, NULL); LineTo(hdc, cxScreen, 0);
1257:   SelectObject(hdc, altstift);
1258:   DeleteObject(stift1); DeleteObject(stift2);
1259: }
1260: 
1261: void SucheBSaufPos(int x, int y, int z)
1262: { char Mldg[200];
1263:   int bs, ct, a, i;
1264:   BAUSTEIN BS;
1265:   MarkierterBS = -1;
1266:   if (!LoesungssatzGueltig) return;
1267:   a = Loesungslage; if (a < 0) a = 0;
1268:   for (ct = 0; ct < BAUSTEINZAHL; ct++) {
1269:     bs = BausteinNummer(Loesungssatz[ct]);
1270:     if ((bs >= 0) && (bs < BAUSTEINZAHL)) {
1271:       BS = BewegterBaustein(Baustein[bs], MatMul(Hinlegen[a], Orientierung(Loesungssatz[ct])));
1272:       for (i = 0; i < BS.Teilwuerfelzahl; i++) {
1273:         if ((BS.Einzelelemente[i].KOORD[0] == x)
1274:          && (BS.Einzelelemente[i].KOORD[1] == y)
1275:          && (BS.Einzelelemente[i].KOORD[2] == z)) {
1276:           MarkierterBS = bs;
1277:           InvalidateRect(hwndApplication, &Bereich1, TRUE);
1278:           sprintf(Mldg, "Der %d. Baustein liegt auf der Raumkoordinate '%d,%d,%d'",
1279:             bs + 1, x, y, z);
1280:           MessageBox(hwndApplication, Mldg, "Positionsinfo:", MB_ICONINFORMATION | MB_OK);
1281:           return;
1282:         }
1283:       }
1284:     }
1285:   }
1286:   InvalidateRect(hwndApplication, &Bereich1, TRUE);
1287: }
1288: 
1289: void SetFilterCoordinate(int x, int y, int z)
1290: { char Positionsstring[16];
1291:   if (!Filter_an || (VorgabeAktivBS < 0) || (VorgabeAktivSp < 0)) return;
1292:   sprintf(Positionsstring, "%d,%d,%d", x, y, z);
1293:   SetWindowText(Vorgaben[VorgabeAktivBS][VorgabeAktivSp], Positionsstring);
1294:   Vorgabenwerte[VorgabeAktivBS][VorgabeAktivSp][0] = x;
1295:   Vorgabenwerte[VorgabeAktivBS][VorgabeAktivSp][1] = y;
1296:   Vorgabenwerte[VorgabeAktivBS][VorgabeAktivSp][2] = z;
1297:   Vorgabenwerte[VorgabeAktivBS][VorgabeAktivSp][3] = 1;
1298:   BitteSuchen = 1;
1299:   if (!SuchtGerade()) SetWindowText(SucheStart, "Suchen!");
1300: }
1301: 
1302: void ButtonPosClickSelect(HWND hwnd, int x, int y)
1303: { int p;
1304:   if ((x <= Grenze1) || (x >= Grenze2)) return;
1305:   p = y - SSy;
1306:   if (p < 0) return;
1307:   p = p / TXy;
1308:   if (p >= SSl) return;
1309:   p += ScrollOffset;
1310:   if (p >= SuchErgebnisse) return;
1311:   /* In die Eingabe zur Darstellung übertragen */
1312:   SetWindowText(Loesung_Nr, ErgebnisString(p));
1313:   ChoosenResult = p;
1314:   InvalidateRect(hwnd, &Bereich2, TRUE);
1315: }
1316: 
1317: void ButtonPosClickTransfer(HWND hwnd, int to_filter, int x, int y)
1318: { int dx, dy, u, v;
1319:   if (x < Grenze2) return;
1320:   /* Loesung eines Gleichungssystem mit 2 Unbekannten nach dem Determinantenverfahren */
1321:   /* oberes Bild */
1322:   dx = x - DI1_cx; dy = y - DI1_cy;
1323:   /* oben */
1324:   u = (  3 * dx - 24 * dy + 219 * DI_scale) / 219 / DI_scale - 1;
1325:   v = ( -8 * dx -  9 * dy + 219 * DI_scale) / 219 / DI_scale - 1;
1326:   if ((u >= 0) && (v >= 0) && (u < 3) && (v < 5)) {
1327:     if (!to_filter) { SucheBSaufPos(4 - v, 3, 2 - u); return; }
1328:     SetFilterCoordinate(4 - v, 3, 2 - u);
1329:     return;
1330:   }
1331:   /* vorne / links */
1332:   u = (-24 * dx           + 576 * DI_scale) / 576 / DI_scale - 1;
1333:   v = ( -3 * dx + 24 * dy + 576 * DI_scale) / 576 / DI_scale - 1;
1334:   if ((u >= 0) && (v >= 0) && (u < 5) && (v < 4)) {
1335:     if (!to_filter) { SucheBSaufPos(4 - u, 3 - v, 2); return; }
1336:     SetFilterCoordinate(4 - u, 3 - v, 2);
1337:     return;
1338:   }
1339:   /* rechts */
1340:   u = ( 24 * dx           + 216 * DI_scale) / 216 / DI_scale - 1;
1341:   v = (  8 * dx +  9 * dy + 216 * DI_scale) / 216 / DI_scale - 1;
1342:   if ((u >= 0) && (v >= 0) && (u < 3) && (v < 4)) {
1343:     if (!to_filter) { SucheBSaufPos(4, 3 - v, 2 - u); return; }
1344:     SetFilterCoordinate(4, 3 - v, 2 - u);
1345:     return;
1346:   }
1347:   /* unteres Bild */
1348:   dx = x - DI2_cx; dy = y - DI2_cy;
1349:   /* oben */
1350:   u = (  8 * dx -  9 * dy + 219 * DI_scale) / 219 / DI_scale - 1;
1351:   v = ( -3 * dx - 24 * dy + 219 * DI_scale) / 219 / DI_scale - 1;
1352:   if ((u >= 0) && (v >= 0) && (u < 5) && (v < 3)) {
1353:     if (!to_filter) { SucheBSaufPos(u, 0, v); return; }
1354:     SetFilterCoordinate(u, 0, v);
1355:     return;
1356:   }
1357:   /* links */
1358:   u = (-24 * dx           + 216 * DI_scale) / 216 / DI_scale - 1;
1359:   v = ( -8 * dx +  9 * dy + 216 * DI_scale) / 216 / DI_scale - 1;
1360:   if ((u >= 0) && (v >= 0) && (u < 3) && (v < 4)) {
1361:     if (!to_filter) { SucheBSaufPos(0, v, u); return; }
1362:     SetFilterCoordinate(0, v, u);
1363:     return;
1364:   }
1365:   /* vorne / rechts */
1366:   u = ( 24 * dx           + 567 * DI_scale) / 576 / DI_scale - 1;
1367:   v = (  3 * dx + 24 * dy + 576 * DI_scale) / 576 / DI_scale - 1;
1368:   if ((u >= 0) && (v >= 0) && (u < 5) && (v < 4)) {
1369:     if (!to_filter) { SucheBSaufPos(u, v, 0); return; }
1370:     SetFilterCoordinate(u, v, 0);
1371:     return;
1372:   }
1373:   if (!to_filter) { MarkierterBS = -1; InvalidateRect(hwnd, &Bereich1, TRUE); }
1374: }
1375: 
1376: LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1377: { HDC hdc;
1378:   PAINTSTRUCT ps;
1379:   switch (uMsg) {
1380:     case WM_PAINT:
1381:       hdc = BeginPaint(hwnd, &ps);
1382:       PaintGlobal(hdc);
1383:       PaintSection1(hdc);
1384:       PaintSection2(hdc);
1385:       PaintSection3(hdc);
1386:       EndPaint(hwnd, &ps);
1387:     return 0;
1388:     case WM_CREATE:
1389:       cxChar = LOWORD(GetDialogBaseUnits());
1390:       cyChar = HIWORD(GetDialogBaseUnits());
1391:       CreateSubwindows(hwnd);
1392:     break;
1393:     case WM_SIZE:
1394:       cxScreen = LOWORD(lParam);
1395:       cyScreen = HIWORD(lParam);
1396:       ChangeSize(hwnd, lParam);
1397:       AdjustScrollbarSize();
1398:     break;
1399:     case WM_COMMAND:
1400:       CommandAction(hwnd, HIWORD(wParam), LOWORD(wParam), lParam);
1401:     break;
1402:     case WM_VSCROLL:
1403:       ScrollAction(hwnd, HIWORD(wParam), LOWORD(wParam), lParam);
1404:     break;
1405:     case WM_RBUTTONDOWN:
1406:       ButtonPosClickTransfer(hwnd, 0, LOWORD(lParam), HIWORD(lParam));
1407:     break;
1408:     case WM_LBUTTONDOWN:
1409:       ButtonPosClickTransfer(hwnd, 1, LOWORD(lParam), HIWORD(lParam));
1410:       ButtonPosClickSelect(hwnd, LOWORD(lParam), HIWORD(lParam));
1411:     break;
1412:     case WM_DESTROY:
1413:       if (Loesungsdatei != NULL) fclose(Loesungsdatei);
1414:       PostQuitMessage(0);
1415:       return 0;
1416:   }
1417:   return DefWindowProc(hwnd, uMsg, wParam, lParam);
1418: }
1419: 
1420: BOOL InsertSubmenuString(HMENU hMenu, UINT Pos, BOOL byPos, HMENU submenu, CHAR *Text)
1421: { MENUITEMINFO mii;
1422:   mii.cbSize = sizeof(MENUITEMINFO);
1423:   mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
1424:   mii.fType = MFT_STRING;
1425:   mii.fState = MFS_DEFAULT;
1426:   mii.wID = 0;
1427:   mii.hSubMenu= submenu;
1428:   mii.hbmpChecked = NULL;
1429:   mii.hbmpUnchecked = NULL;
1430:   mii.dwItemData = 0;
1431:   mii.dwTypeData = Text;
1432:   mii.cch = strlen(Text);
1433:   return InsertMenuItem(hMenu, Pos, byPos, &mii);
1434: }
1435: 
1436: void BuildMenu(HWND hwnd)
1437: { HMENU newmenu, oldmenu, submenu;
1438: 
1439:   newmenu = CreateMenu();
1440: 
1441:   AppendMenu(newmenu, MF_STRING, MN_START_SUCHE, "&Lösungssuche starten");
1442: 
1443:   SpiegelMenu = CreateMenu();
1444:   AppendMenu(SpiegelMenu, MF_STRING, MN_MIRROR_1, "&C-Teil umdrehen");
1445:   AppendMenu(SpiegelMenu, MF_STRING, MN_MIRROR_2, "&Z-Teil umdrehen");
1446:   AppendMenu(SpiegelMenu, MF_STRING, MN_MIRROR_9, "&r-Teil umdrehen");
1447:   InsertSubmenuString(newmenu, -1, TRUE, SpiegelMenu, "&Bausteinspiegelungen");
1448: 
1449:   submenu = CreateMenu();
1450:   AppendMenu(submenu, MF_STRING, MN_FILTER_CLEAR, "alle Filter &löschen");
1451:   AppendMenu(submenu, MF_STRING, MN_FILTER_A_B, "wenden a/&b und c/d");
1452:   AppendMenu(submenu, MF_STRING, MN_FILTER_A_C, "wenden a/&c und b/d");
1453:   AppendMenu(submenu, MF_STRING, MN_FILTER_A_D, "wenden a/&d und b/c");
1454:   InsertSubmenuString(newmenu, -1, TRUE, submenu, "&Filtermanipulationen");
1455: 
1456:   DimetrieMenu = CreateMenu();
1457:   AppendMenu(DimetrieMenu, MF_STRING, MN_DIMET_S1, "Zoomfaktor &1");
1458:   AppendMenu(DimetrieMenu, MF_STRING, MN_DIMET_S2, "Zoomfaktor &2");
1459:   AppendMenu(DimetrieMenu, MF_STRING, MN_DIMET_S3, "Zoomfaktor &3");
1460:   InsertSubmenuString(newmenu, -1, TRUE, DimetrieMenu, "&Dimetrische Darstellungen");
1461: 
1462:   AppendMenu(newmenu, MF_STRING, MN_INFO, "&Hinweise");
1463: 
1464:   oldmenu = GetMenu(hwnd);
1465:   SetMenu(hwnd, newmenu);
1466:   DestroyMenu(oldmenu);
1467:   DrawMenuBar(hwnd);
1468: }
1469: 
1470: #pragma argsused
1471: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR d3, int nCmdShow)
1472: { 
1473:   MSG msg;
1474:   WNDCLASSEX wndClass;
1475:   // HBRUSH BackgroundColor;

1476: 
1477:   hThisInstance = hInstance;
1478:   IconGross = CreateIconString(hInstance, 32, 32, 2, 2, 0,
1479:                 "                "
1480:                 "                "
1481:                 "KKKKKKKKKKKKKKKK"
1482:                 "K..K..KRRKR.K..K"
1483:                 "K..K..KRRKR.K..K"
1484:                 "KKKKKKK.RKR.KKKK"
1485:                 "K..RRRK.RKRRRRRK"
1486:                 "K.R...KR.KR....K"
1487:                 "KR.KKKKKKKR.KKKK"
1488:                 "KR.K.....KR.K..K"
1489:                 "KR.K.....KR.K..K"
1490:                 "KR.KKKKKKKR.KKKK"
1491:                 "K.R...K..K.R...K"
1492:                 "K..RRRK..K..RRRK"
1493:                 "KKKKKKKKKKKKKKKK"
1494:                 "                ");
1495:   IconKlein = CreateIconString(hInstance, 16, 16, 1, 1, 0,
1496:                 "                "
1497:                 "                "
1498:                 "KKKKKKKKKKKKKKKK"
1499:                 "K..K..KRRKR.K..K"
1500:                 "K..K..KRRKR.K..K"
1501:                 "KKKKKKK.RKR.KKKK"
1502:                 "K..RRRK.RKRRRRRK"
1503:                 "K.R...KR.KR....K"
1504:                 "KR.KKKKKKKR.KKKK"
1505:                 "KR.K.....KR.K..K"
1506:                 "KR.K.....KR.K..K"
1507:                 "KR.KKKKKKKR.KKKK"
1508:                 "K.R...K..K.R...K"
1509:                 "K..RRRK..K..RRRK"
1510:                 "KKKKKKKKKKKKKKKK"
1511:                 "                ");
1512:   if (hPrevInstance == NULL) {
1513:     memset(&wndClass, 0, sizeof(WNDCLASSEX));
1514:     wndClass.cbSize        = sizeof(WNDCLASSEX);
1515:     wndClass.style         = CS_HREDRAW | CS_VREDRAW;
1516:     wndClass.lpfnWndProc   = WndProc;
1517:     wndClass.cbClsExtra    = 0;
1518:     wndClass.cbWndExtra    = 0;
1519:     wndClass.hInstance     = hInstance;
1520:     wndClass.hIcon         = IconGross;
1521:     wndClass.hIconSm       = IconKlein;
1522:     wndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
1523:     wndClass.hbrBackground = /* BackgroundColor = CreateSolidBrush(RGB(0, 0, 128)); */ (HBRUSH) (COLOR_MENU + 1);
1524:     wndClass.lpszMenuName  = NULL;
1525:     wndClass.lpszClassName = ThisClassName;
1526:     if (!RegisterClassEx(&wndClass)) {
1527:       MessageBox(NULL, "RegisterClass() schlug fehl!", "Prinzipielle Startprobleme",
1528:       MB_ICONEXCLAMATION | MB_OK);
1529:       return 1;
1530:     }
1531:   }
1532: 
1533:   HintergrundLeiste = CreateSolidBrush(RGB(0, 0, 128));
1534: 
1535:   hwndApplication = CreateWindow(ThisClassName, ThisTitleBar,
1536:     WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
1537:     CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
1538:     NULL, NULL, hInstance, NULL);
1539:   BuildMenu(hwndApplication);
1540:   SetDimetScale(1);
1541:   ShowWindow(hwndApplication, nCmdShow);
1542:   UpdateWindow(hwndApplication);
1543:   if (access(ERGEBNIS, 4)) StartLoesungsBerechnung(1);
1544: 
1545:   while (GetMessage(&msg, NULL, 0, 0)) {
1546:     TranslateMessage(&msg);
1547:     DispatchMessage(&msg);
1548:   }
1549: 
1550:   return msg.wParam;
1551: }
1552: 
1553: