1844 lines
38 KiB
C
1844 lines
38 KiB
C
/*
|
|
Space Group Info's (c) 1994-96 Ralf W. Grosse-Kunstleve
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
|
|
#define SGCOREDEF__
|
|
#include "sginfo.h"
|
|
|
|
|
|
typedef struct {
|
|
int OriginChoice;
|
|
int CellChoice;
|
|
int BasisChoice;
|
|
const char *BT_or_UA;
|
|
} T_ExtInfo;
|
|
|
|
|
|
static const char *Ext_BT_or_UA[] = {
|
|
/* 0 */ "abc",
|
|
/* 1 */ "ba-c",
|
|
/* 2 */ "cab",
|
|
/* 3 */ "-cba",
|
|
/* 4 */ "bca",
|
|
/* 5 */ "a-cb",
|
|
/* 6 */ "bac",
|
|
/* 6 -> 1 */
|
|
/* 7 */ "cba",
|
|
/* 7 -> 3 */
|
|
/* 8 */ "acb",
|
|
/* 8 -> 5 */
|
|
/* 9 */ "-b", "b-", "bb", "bb",
|
|
/* 10, 11, 12 -> 9 */
|
|
/* 13 */ "-c", "c-", "bc", "cb",
|
|
/* 14, 15, 16 -> 13 */
|
|
/* 17 */ "-a", "a-", "ba", "ab",
|
|
/* 18, 19, 20 -> 17 */
|
|
/* 21 */ "b",
|
|
/* 22 */ "c",
|
|
/* 23 */ "a",
|
|
NULL
|
|
};
|
|
|
|
|
|
typedef struct {
|
|
int Improper, Rotation, RefAxis, DirCode, Screw;
|
|
T_RTMx SeitzMx;
|
|
} T_HallGenerator;
|
|
|
|
|
|
#define SkipWhite(cp) while (*(cp) && (*(cp) == '_' || isspace(*(cp)))) (cp)++
|
|
|
|
|
|
static const char *IErr_Corrupt_TabSgName =
|
|
"Internal Error: Corrupt TabSgName";
|
|
|
|
|
|
static int FindSchoenfliesSymbol(const char *SfSymbol)
|
|
{
|
|
int SgNumber;
|
|
const char **TabSymbol;
|
|
const char *s, *t;
|
|
|
|
|
|
TabSymbol = SchoenfliesSymbols + 1;
|
|
|
|
for (SgNumber = 1; SgNumber <= 230; SgNumber++) {
|
|
t = *TabSymbol;
|
|
s = SfSymbol;
|
|
|
|
while (*t && *s) {
|
|
if (toupper(*t) != toupper(*s)
|
|
&& (*t != '^' || isalpha(*s) || isdigit(*s)))
|
|
break;
|
|
|
|
t++;
|
|
s++;
|
|
}
|
|
|
|
if (*t == *s)
|
|
return SgNumber;
|
|
|
|
TabSymbol++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int SgLabelCmp(const int SgNumber,
|
|
const char *SgLabel, const char *WtdLbl)
|
|
{
|
|
const char *sgl, *wl;
|
|
|
|
|
|
/* first try: plain strcmp
|
|
*/
|
|
sgl = SgLabel;
|
|
|
|
for (wl = WtdLbl;; wl++) {
|
|
SkipWhite(wl);
|
|
SkipWhite(sgl);
|
|
|
|
if (*sgl == '\0' || *sgl == '=') {
|
|
if (*wl == '\0')
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
if (*sgl == '-') {
|
|
if (*wl != '-' && toupper(*wl) != 'B')
|
|
break;
|
|
} else if (toupper(*sgl) != toupper(*wl))
|
|
break;
|
|
|
|
sgl++;
|
|
}
|
|
|
|
/* second try: swap the dash (there should be only one)
|
|
*/
|
|
sgl = SgLabel;
|
|
|
|
for (wl = WtdLbl;; wl++) {
|
|
SkipWhite(wl);
|
|
SkipWhite(sgl);
|
|
|
|
if (*sgl == '-') {
|
|
if (wl[1] != '-' && toupper(wl[1]) != 'B')
|
|
break;
|
|
if (toupper(sgl[1]) != toupper(*wl))
|
|
break;
|
|
|
|
sgl++;
|
|
wl++;
|
|
} else {
|
|
if (*sgl == '\0' || *sgl == '=') {
|
|
if (*wl == '\0')
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
if (toupper(*sgl) != toupper(*wl))
|
|
break;
|
|
}
|
|
|
|
sgl++;
|
|
}
|
|
|
|
if (SgNumber >= 195) { /* cubic space groups only */
|
|
/* third try: ignore the "-3" dash
|
|
*/
|
|
sgl = SgLabel;
|
|
|
|
for (wl = WtdLbl;; wl++) {
|
|
SkipWhite(wl);
|
|
SkipWhite(sgl);
|
|
|
|
if (*sgl == '-' && sgl[1] == '3')
|
|
sgl++;
|
|
|
|
if (*sgl == '\0' || *sgl == '=') {
|
|
if (*wl == '\0')
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
if (toupper(*sgl) != toupper(*wl))
|
|
break;
|
|
|
|
sgl++;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int ParseExtension(const char *Ext, T_ExtInfo * ExtInfo)
|
|
{
|
|
int i, mode;
|
|
const char *e, *t;
|
|
|
|
|
|
ExtInfo->OriginChoice = ExtInfo->CellChoice = ExtInfo->BasisChoice = ' ';
|
|
ExtInfo->BT_or_UA = "";
|
|
|
|
mode = 0;
|
|
|
|
while (*Ext) {
|
|
if (strchr("12", *Ext) != NULL) {
|
|
ExtInfo->CellChoice = ExtInfo->OriginChoice = *Ext++;
|
|
} else if (strchr("3", *Ext) != NULL) {
|
|
ExtInfo->CellChoice = *Ext++;
|
|
} else if (strchr("Ss", *Ext) != NULL) {
|
|
ExtInfo->OriginChoice = '1';
|
|
Ext++;
|
|
} else if (strchr("Zz", *Ext) != NULL) {
|
|
ExtInfo->OriginChoice = '2';
|
|
Ext++;
|
|
} else if (strchr("Hh", *Ext) != NULL) {
|
|
ExtInfo->BasisChoice = 'H';
|
|
Ext++;
|
|
} else if (strchr("Rr", *Ext) != NULL) {
|
|
ExtInfo->BasisChoice = 'R';
|
|
Ext++;
|
|
} else if (mode == 0)
|
|
mode = 1;
|
|
|
|
if (mode == 2)
|
|
break;
|
|
|
|
for (i = 0; Ext_BT_or_UA[i]; i++) {
|
|
for (e = Ext, t = Ext_BT_or_UA[i]; *t; e++, t++)
|
|
if (toupper(*e) != toupper(*t))
|
|
break;
|
|
|
|
if (*t == '\0') {
|
|
if (6 <= i && i <= 8)
|
|
i = 2 * i - 11;
|
|
else if (9 <= i && i <= 20)
|
|
i = 9 + ((i - 9) / 4) * 4;
|
|
|
|
ExtInfo->BT_or_UA = Ext_BT_or_UA[i];
|
|
Ext = e;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mode == 0)
|
|
break;
|
|
|
|
mode = 2;
|
|
}
|
|
|
|
if (*Ext)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void ExpandMonoclinic(int unique_axis, const char *o, char *m)
|
|
{
|
|
if (*o)
|
|
*m++ = *o++;
|
|
|
|
switch (tolower(unique_axis)) {
|
|
case 'a':
|
|
while (*o)
|
|
*m++ = *o++;
|
|
*m++ = '1';
|
|
*m++ = '1';
|
|
break;
|
|
case 'c':
|
|
*m++ = '1';
|
|
*m++ = '1';
|
|
while (*o)
|
|
*m++ = *o++;
|
|
break;
|
|
default:
|
|
*m++ = '1';
|
|
while (*o)
|
|
*m++ = *o++;
|
|
*m++ = '1';
|
|
break;
|
|
}
|
|
|
|
*m = '\0';
|
|
}
|
|
|
|
|
|
const T_TabSgName *FindTabSgNameEntry(const char *UserSgName,
|
|
int VolLetter)
|
|
{
|
|
#define MaxWtdLbl 20
|
|
char WtdLblOriginal[MaxWtdLbl + 1];
|
|
char WtdLblModified[MaxWtdLbl + 1];
|
|
char *WtdLbl;
|
|
#define MaxWtdExt 5
|
|
char WtdExt[MaxWtdExt + 1];
|
|
int WtdSgNumber;
|
|
int WtdLblOriginChoice;
|
|
int WtdLblBasisChoice;
|
|
int iwl, iwe;
|
|
char *wl, *we;
|
|
|
|
int i, IsExpanded, lbl_match;
|
|
const char *sgl;
|
|
const T_TabSgName *tsgn;
|
|
int WtdCC;
|
|
const char *WtdUA;
|
|
char WtdUA_Buf[2];
|
|
T_ExtInfo ExtInfo, WtdExtInfo;
|
|
|
|
|
|
if (VolLetter == 0 || isspace(VolLetter))
|
|
VolLetter = 'A';
|
|
else if (VolLetter == '1')
|
|
VolLetter = 'I';
|
|
else {
|
|
VolLetter = toupper(VolLetter);
|
|
if (VolLetter != 'I' && VolLetter != 'A')
|
|
return NULL;
|
|
}
|
|
|
|
WtdLbl = WtdLblOriginal;
|
|
|
|
wl = WtdLbl;
|
|
iwl = 0;
|
|
|
|
while (*UserSgName && *UserSgName != ':') {
|
|
if (isspace(*UserSgName) == 0 && *UserSgName != '_') {
|
|
if (iwl >= MaxWtdLbl)
|
|
return NULL;
|
|
|
|
*wl++ = *UserSgName;
|
|
iwl++;
|
|
}
|
|
|
|
UserSgName++;
|
|
}
|
|
|
|
*wl = '\0';
|
|
|
|
if (iwl == 0)
|
|
return NULL;
|
|
|
|
we = WtdExt;
|
|
iwe = 0;
|
|
*we = '\0';
|
|
|
|
if (*UserSgName) {
|
|
UserSgName++;
|
|
|
|
while (*UserSgName) {
|
|
if (isspace(*UserSgName) == 0 && *UserSgName != '_') {
|
|
if (iwe >= MaxWtdExt)
|
|
return NULL;
|
|
|
|
*we++ = *UserSgName;
|
|
iwe++;
|
|
}
|
|
|
|
UserSgName++;
|
|
}
|
|
}
|
|
|
|
*we = '\0';
|
|
|
|
WtdLblOriginChoice = ' ';
|
|
WtdLblBasisChoice = ' ';
|
|
|
|
if (iwl > 1) {
|
|
wl = &WtdLbl[iwl - 1];
|
|
|
|
if (*wl == 'S' || *wl == 's') {
|
|
WtdLblOriginChoice = '1';
|
|
*wl = '\0';
|
|
iwl--;
|
|
} else if (*wl == 'Z' || *wl == 'z') {
|
|
WtdLblOriginChoice = '2';
|
|
*wl = '\0';
|
|
iwl--;
|
|
} else if (*wl == 'H' || *wl == 'h') {
|
|
WtdLblBasisChoice = 'H';
|
|
*wl = '\0';
|
|
iwl--;
|
|
} else if (*wl == 'R' || *wl == 'r') {
|
|
WtdLblBasisChoice = 'R';
|
|
*wl = '\0';
|
|
iwl--;
|
|
}
|
|
}
|
|
|
|
if (isalpha(WtdLbl[0]))
|
|
WtdSgNumber = FindSchoenfliesSymbol(WtdLbl);
|
|
else {
|
|
for (wl = WtdLbl; *wl; wl++)
|
|
if (isdigit(*wl) == 0)
|
|
return NULL;
|
|
|
|
if (sscanf(WtdLbl, "%d", &WtdSgNumber) != 1
|
|
|| WtdSgNumber < 1 || WtdSgNumber > 230)
|
|
return NULL;
|
|
}
|
|
|
|
if (ParseExtension(WtdExt, &WtdExtInfo) != 0)
|
|
return NULL;
|
|
|
|
if (WtdExtInfo.OriginChoice == ' ')
|
|
WtdExtInfo.OriginChoice = WtdLblOriginChoice;
|
|
else if (WtdExtInfo.OriginChoice != WtdLblOriginChoice
|
|
&& WtdLblOriginChoice != ' ')
|
|
return NULL;
|
|
|
|
if (WtdExtInfo.BasisChoice == ' ')
|
|
WtdExtInfo.BasisChoice = WtdLblBasisChoice;
|
|
else if (WtdExtInfo.BasisChoice != WtdLblBasisChoice
|
|
&& WtdLblBasisChoice != ' ')
|
|
return NULL;
|
|
|
|
if (WtdExtInfo.OriginChoice != ' ' && WtdExtInfo.BasisChoice != ' ')
|
|
return NULL;
|
|
|
|
for (IsExpanded = 0; IsExpanded < 4; IsExpanded++) {
|
|
for (tsgn = TabSgName; tsgn->HallSymbol; tsgn++) {
|
|
if (IsExpanded != 0 && tsgn->SgNumber > 15)
|
|
break;
|
|
|
|
lbl_match = 0;
|
|
|
|
if (WtdSgNumber == -1) {
|
|
i = 1;
|
|
sgl = tsgn->SgLabels;
|
|
while (*sgl && i <= 2) {
|
|
while (*sgl && strchr(" =\t", *sgl) != NULL)
|
|
sgl++;
|
|
|
|
if (SgLabelCmp(tsgn->SgNumber, sgl, WtdLbl) == 0) {
|
|
lbl_match = i;
|
|
break;
|
|
}
|
|
|
|
while (*sgl && strchr(" =\t", *sgl) == NULL)
|
|
sgl++;
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (ParseExtension(tsgn->Extension, &ExtInfo) != 0) {
|
|
SetSgError(IErr_Corrupt_TabSgName);
|
|
return NULL;
|
|
}
|
|
|
|
if (WtdSgNumber == tsgn->SgNumber || lbl_match != 0) {
|
|
if (tsgn->SgNumber >= 3 && tsgn->SgNumber < 16) {
|
|
if (WtdLblOriginChoice != ' '
|
|
|| WtdExtInfo.BasisChoice != ' '
|
|
|| (int) strlen(WtdExtInfo.BT_or_UA) > 2)
|
|
continue; /* next tsgn */
|
|
|
|
if (WtdSgNumber == tsgn->SgNumber) {
|
|
if (WtdExtInfo.BT_or_UA[0])
|
|
WtdUA = WtdExtInfo.BT_or_UA;
|
|
else if (VolLetter == 'I') {
|
|
if (ExtInfo.BT_or_UA[0] != 'c' && ExtInfo.BT_or_UA[1] != 'c')
|
|
continue; /* next tsgn */
|
|
|
|
if (ExtInfo.CellChoice == ' '
|
|
&& (WtdExtInfo.CellChoice == ' '
|
|
|| WtdExtInfo.CellChoice == '1'))
|
|
return tsgn;
|
|
|
|
i = 0;
|
|
for (sgl = tsgn->SgLabels; *sgl; sgl++)
|
|
if (*sgl == '=')
|
|
i++;
|
|
|
|
if (i == 2
|
|
&& (WtdExtInfo.CellChoice == ' '
|
|
|| WtdExtInfo.CellChoice == ExtInfo.CellChoice))
|
|
return tsgn;
|
|
|
|
continue; /* next tsgn */
|
|
} else
|
|
WtdUA = "b";
|
|
} else { /* if (lbl_match != 0) */
|
|
|
|
if (WtdExtInfo.BT_or_UA[0])
|
|
WtdUA = WtdExtInfo.BT_or_UA;
|
|
else if (lbl_match > 1)
|
|
WtdUA = ExtInfo.BT_or_UA;
|
|
else if (VolLetter == 'I' && ExtInfo.CellChoice == ' ')
|
|
WtdUA = "c";
|
|
else
|
|
WtdUA = "b";
|
|
}
|
|
|
|
if (WtdExtInfo.CellChoice != ' ')
|
|
WtdCC = WtdExtInfo.CellChoice;
|
|
else if (ExtInfo.CellChoice == '1')
|
|
WtdCC = ExtInfo.CellChoice;
|
|
else
|
|
WtdCC = ' ';
|
|
|
|
if (strcmp(ExtInfo.BT_or_UA, WtdUA) == 0) {
|
|
if (WtdCC == ' ' && lbl_match > 1)
|
|
return tsgn;
|
|
if (ExtInfo.CellChoice == WtdCC)
|
|
return tsgn;
|
|
if (ExtInfo.CellChoice == ' ' && WtdCC == '1')
|
|
return tsgn;
|
|
if (ExtInfo.CellChoice == '1' && WtdCC == ' ')
|
|
return tsgn;
|
|
}
|
|
} else if (ExtInfo.BasisChoice != ' ') {
|
|
if (WtdExtInfo.OriginChoice != ' '
|
|
|| WtdExtInfo.CellChoice != ' '
|
|
|| WtdExtInfo.BT_or_UA[0] != '\0')
|
|
continue; /* next tsgn */
|
|
|
|
if (ExtInfo.BasisChoice == WtdExtInfo.BasisChoice)
|
|
return tsgn;
|
|
|
|
if (WtdExtInfo.BasisChoice == ' ') {
|
|
if (ExtInfo.BasisChoice == 'R' && VolLetter == 'I')
|
|
return tsgn;
|
|
if (ExtInfo.BasisChoice == 'H' && VolLetter != 'I')
|
|
return tsgn;
|
|
}
|
|
} else if (WtdExtInfo.BasisChoice == ' ') {
|
|
if ((WtdExtInfo.OriginChoice == ' '
|
|
&& ExtInfo.OriginChoice == '1')
|
|
|| (WtdExtInfo.OriginChoice == '1'
|
|
&& ExtInfo.OriginChoice == ' ')
|
|
|| WtdExtInfo.OriginChoice == ExtInfo.OriginChoice) {
|
|
if (WtdExtInfo.BT_or_UA[0]) {
|
|
if (WtdExtInfo.BT_or_UA == ExtInfo.BT_or_UA)
|
|
return tsgn;
|
|
if (WtdExtInfo.BT_or_UA == Ext_BT_or_UA[0]
|
|
&& ExtInfo.BT_or_UA[0] == '\0')
|
|
return tsgn;
|
|
} else {
|
|
if (lbl_match != 0)
|
|
return tsgn;
|
|
if (ExtInfo.BT_or_UA[0] == '\0')
|
|
return tsgn;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (WtdSgNumber != -1)
|
|
return NULL;
|
|
|
|
if ((int) strlen(WtdExtInfo.BT_or_UA) > 2)
|
|
return NULL;
|
|
|
|
if (IsExpanded == 0) {
|
|
iwl += 2;
|
|
|
|
if (iwl > MaxWtdLbl)
|
|
IsExpanded = 2;
|
|
else {
|
|
if (WtdExtInfo.BT_or_UA[0])
|
|
WtdUA = WtdExtInfo.BT_or_UA;
|
|
else {
|
|
if (VolLetter == 'I')
|
|
WtdUA = "c";
|
|
else
|
|
WtdUA = "b";
|
|
}
|
|
|
|
ExpandMonoclinic(WtdUA[0], WtdLblOriginal, WtdLblModified);
|
|
|
|
WtdLbl = WtdLblModified;
|
|
}
|
|
} else if (IsExpanded == 1) {
|
|
if (WtdExtInfo.BT_or_UA[0])
|
|
return NULL;
|
|
|
|
if (VolLetter == 'I')
|
|
WtdUA = "b";
|
|
else
|
|
WtdUA = "c";
|
|
|
|
ExpandMonoclinic(WtdUA[0], WtdLblOriginal, WtdLblModified);
|
|
}
|
|
|
|
if (IsExpanded == 2) {
|
|
if (WtdExtInfo.BT_or_UA[0])
|
|
return NULL;
|
|
|
|
iwl -= 2;
|
|
|
|
if (iwl < 2)
|
|
return NULL;
|
|
iwl--;
|
|
WtdUA_Buf[0] = tolower(WtdLblOriginal[iwl]);
|
|
WtdLblOriginal[iwl] = '\0';
|
|
WtdUA_Buf[1] = '\0';
|
|
|
|
if (strchr("abc", WtdUA_Buf[0]) == NULL)
|
|
return NULL;
|
|
|
|
WtdUA = WtdUA_Buf;
|
|
|
|
iwl += 2;
|
|
|
|
if (iwl > MaxWtdLbl)
|
|
return NULL;
|
|
|
|
ExpandMonoclinic(WtdUA[0], WtdLblOriginal, WtdLblModified);
|
|
|
|
WtdLbl = WtdLblModified;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
unsigned int SgID_Number(const T_TabSgName * tsgn)
|
|
{
|
|
unsigned int ID;
|
|
int iBT;
|
|
const char *UA;
|
|
T_ExtInfo ExtInfo;
|
|
|
|
|
|
ID = tsgn->SgNumber;
|
|
|
|
if (ParseExtension(tsgn->Extension, &ExtInfo) != 0)
|
|
ID = 0;
|
|
|
|
if (ID >= 3 && ID < 16) {
|
|
UA = ExtInfo.BT_or_UA;
|
|
|
|
if (*UA != 'b'
|
|
|| (ExtInfo.CellChoice != ' ' && ExtInfo.CellChoice != '1')) {
|
|
if (*UA == '-') {
|
|
ID += 3000;
|
|
UA++;
|
|
}
|
|
|
|
switch (*UA) {
|
|
case 'b':
|
|
ID += 10000;
|
|
break;
|
|
case 'c':
|
|
ID += 20000;
|
|
break;
|
|
case 'a':
|
|
ID += 30000;
|
|
break;
|
|
default:
|
|
ID = 0;
|
|
break;
|
|
}
|
|
|
|
if (ID != 0) {
|
|
switch (ExtInfo.CellChoice) {
|
|
case ' ':
|
|
break;
|
|
case '1':
|
|
ID += 1000;
|
|
break;
|
|
case '2':
|
|
ID += 2000;
|
|
break;
|
|
case '3':
|
|
ID += 3000;
|
|
break;
|
|
default:
|
|
ID = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (ExtInfo.BasisChoice == 'R')
|
|
ID += 20000;
|
|
else {
|
|
if (ExtInfo.BT_or_UA[0]) {
|
|
for (iBT = 0; iBT < 6; iBT++)
|
|
if (ExtInfo.BT_or_UA == Ext_BT_or_UA[iBT])
|
|
break;
|
|
} else
|
|
iBT = 0;
|
|
|
|
if (iBT < 6) {
|
|
if (ExtInfo.OriginChoice == '2')
|
|
ID += 20000;
|
|
else if (iBT)
|
|
ID += 10000;
|
|
|
|
if (iBT)
|
|
ID += (iBT + 1) * 1000;
|
|
} else
|
|
ID = 0;
|
|
}
|
|
}
|
|
|
|
if (ID == 0)
|
|
SetSgError(IErr_Corrupt_TabSgName);
|
|
|
|
return ID;
|
|
}
|
|
|
|
|
|
int ParseSymXYZ(const char *SymXYZ, T_RTMx * SeitzMx, int FacTr)
|
|
{
|
|
unsigned int P_mode;
|
|
int Row, Column, Sign, GotXYZ, i;
|
|
double Value, Value1, Value2, Delta;
|
|
|
|
|
|
for (i = 0; i < 12; i++)
|
|
SeitzMx->a[i] = 0;
|
|
|
|
#define P_Blank 0x01u
|
|
#define P_Comma 0x02u
|
|
#define P_Plus 0x04u
|
|
#define P_Dash 0x08u
|
|
#define P_Slash 0x10u
|
|
#define P_Value1 0x20u
|
|
#define P_Value2 0x40u
|
|
#define P_XYZ 0x80u
|
|
|
|
Value1 = 0.;
|
|
|
|
Row = 0;
|
|
Sign = 1;
|
|
Value = 0.;
|
|
GotXYZ = 0;
|
|
P_mode = P_Blank | P_Plus | P_Dash | P_Value1 | P_XYZ;
|
|
|
|
do {
|
|
switch (*SymXYZ) {
|
|
case ' ':
|
|
case '\t':
|
|
case '_':
|
|
if ((P_mode & P_Blank) == 0)
|
|
return -1;
|
|
break;
|
|
case ',':
|
|
case ';':
|
|
if (Row == 2)
|
|
return -1;
|
|
case '\0':
|
|
if ((P_mode & P_Comma) == 0)
|
|
return -1;
|
|
if (GotXYZ == 0)
|
|
return -1;
|
|
if (P_mode & P_Slash)
|
|
Value += Value1;
|
|
Value *= FacTr;
|
|
if (Value < 0.)
|
|
i = Value - .5;
|
|
else
|
|
i = Value + .5;
|
|
Delta = Value - i;
|
|
if (Delta < 0.)
|
|
Delta = -Delta;
|
|
if (Delta > .01 * FacTr)
|
|
return -1;
|
|
i %= FacTr;
|
|
if (i < 0)
|
|
i += FacTr;
|
|
SeitzMx->s.T[Row] = i;
|
|
Row++;
|
|
Sign = 1;
|
|
Value = 0.;
|
|
P_mode = P_Blank | P_Plus | P_Dash | P_Value1 | P_XYZ;
|
|
GotXYZ = 0;
|
|
break;
|
|
case '+':
|
|
if ((P_mode & P_Plus) == 0)
|
|
return -1;
|
|
if (P_mode & P_Slash)
|
|
Value += Value1;
|
|
Sign = 1;
|
|
if (P_mode & P_Value2)
|
|
P_mode = P_Value2;
|
|
else
|
|
P_mode = P_Blank | P_Value1 | P_XYZ;
|
|
break;
|
|
case '-':
|
|
if ((P_mode & P_Dash) == 0)
|
|
return -1;
|
|
if (P_mode & P_Slash)
|
|
Value += Value1;
|
|
Sign = -1;
|
|
if (P_mode & P_Value2)
|
|
P_mode = P_Value2;
|
|
else
|
|
P_mode = P_Blank | P_Value1 | P_XYZ;
|
|
break;
|
|
case '/':
|
|
case ':':
|
|
if ((P_mode & P_Slash) == 0)
|
|
return -1;
|
|
Sign = 1;
|
|
P_mode = P_Blank | P_Plus | P_Dash | P_Value2;
|
|
break;
|
|
case '.':
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (P_mode & P_Value1) {
|
|
if (sscanf(SymXYZ, "%lf%n", &Value1, &i) != 1)
|
|
return -1;
|
|
if (Sign == -1)
|
|
Value1 = -Value1;
|
|
P_mode = P_Blank | P_Comma | P_Plus | P_Dash | P_Slash;
|
|
} else if (P_mode & P_Value2) {
|
|
if (sscanf(SymXYZ, "%lf%n", &Value2, &i) != 1)
|
|
return -1;
|
|
if (Sign == -1)
|
|
Value2 = -Value2;
|
|
if (Value1 != 0.) {
|
|
if (Value2 == 0.)
|
|
return -1;
|
|
Value += Value1 / Value2;
|
|
}
|
|
P_mode = P_Blank | P_Comma | P_Plus | P_Dash;
|
|
} else
|
|
return -1;
|
|
SymXYZ += (i - 1);
|
|
break;
|
|
case 'X':
|
|
case 'x':
|
|
Column = 0;
|
|
goto Process_XYZ;
|
|
case 'Y':
|
|
case 'y':
|
|
Column = 1;
|
|
goto Process_XYZ;
|
|
case 'Z':
|
|
case 'z':
|
|
Column = 2;
|
|
Process_XYZ:
|
|
if ((P_mode & P_XYZ) == 0)
|
|
return -1;
|
|
i = Row * 3 + Column;
|
|
if (SeitzMx->s.R[i] != 0)
|
|
return -1;
|
|
SeitzMx->s.R[i] = Sign;
|
|
GotXYZ = 1;
|
|
P_mode = P_Blank | P_Comma | P_Plus | P_Dash;
|
|
break;
|
|
}
|
|
}
|
|
while (*SymXYZ++);
|
|
|
|
if (Row != 3)
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
#undef P_Blank
|
|
#undef P_Comma
|
|
#undef P_Plus
|
|
#undef P_Dash
|
|
#undef P_Slash
|
|
#undef P_Value1
|
|
#undef P_Value2
|
|
#undef P_XYZ
|
|
}
|
|
|
|
|
|
static int LookupRotMx(T_HallGenerator * HG)
|
|
{
|
|
int i, f, refaxis, dircode;
|
|
int iNextBasis, nNextBasis;
|
|
const T_TabXtalRotMx *txrmx;
|
|
|
|
|
|
if (HG->Rotation <= 0)
|
|
return 0;
|
|
|
|
refaxis = HG->RefAxis;
|
|
dircode = HG->DirCode;
|
|
|
|
if (HG->Rotation == 1) {
|
|
refaxis = 'o';
|
|
dircode = '.';
|
|
nNextBasis = 0;
|
|
} else if (dircode == '*') {
|
|
if (refaxis == 0)
|
|
refaxis = 'o';
|
|
nNextBasis = 0;
|
|
} else {
|
|
if (dircode == 0)
|
|
dircode = '=';
|
|
|
|
switch (refaxis) {
|
|
case 'z':
|
|
nNextBasis = 0;
|
|
break;
|
|
case 'x':
|
|
nNextBasis = 1;
|
|
break;
|
|
case 'y':
|
|
nNextBasis = 2;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (txrmx = TabXtalRotMx; txrmx->Order; txrmx++)
|
|
if (txrmx->Order == HG->Rotation)
|
|
break;
|
|
|
|
while (txrmx->Order == HG->Rotation) {
|
|
if (txrmx->DirCode == dircode) {
|
|
if (HG->Improper == 0)
|
|
f = 1;
|
|
else
|
|
f = -1;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
HG->SeitzMx.s.R[i] = txrmx->RMx[i] * f;
|
|
|
|
for (iNextBasis = 0; iNextBasis < nNextBasis; iNextBasis++)
|
|
RotateRotMx(HG->SeitzMx.s.R, RMx_3_111, RMx_3i111);
|
|
|
|
return 1;
|
|
}
|
|
|
|
txrmx++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int ParseHallSymbol(const char *hsym, T_SgInfo * SgInfo)
|
|
{
|
|
int c, i, pos_hsym;
|
|
const int *ht;
|
|
int Centric;
|
|
const T_LatticeInfo *LatticeInfo;
|
|
int FieldType, PreviousFT;
|
|
int iOriginShift, SignOriginShift;
|
|
int digit, rotation, refaxis, dircode;
|
|
const int *translation;
|
|
int PreviousRotation, PreviousRefAxis;
|
|
int nHG, ClearHG;
|
|
T_HallGenerator HG;
|
|
|
|
enum ListOfFieldTypes {
|
|
FT_Delimiter,
|
|
FT_Improper,
|
|
FT_Digit,
|
|
FT_Rotation,
|
|
FT_RefAxis,
|
|
FT_DirCode,
|
|
FT_Translation,
|
|
FT_OriginShift
|
|
};
|
|
|
|
static const char *Err_Ill_ori_shi_val =
|
|
"Error: Illegal origin shift value";
|
|
|
|
static const char *Err_Too_ori_shi_val =
|
|
"Error: Too much origin shift values";
|
|
|
|
|
|
Centric = 0;
|
|
LatticeInfo = NULL;
|
|
|
|
HG.Rotation = HG.RefAxis = HG.DirCode = HG.Screw = 0;
|
|
|
|
nHG = 0;
|
|
ClearHG = 1;
|
|
FieldType = FT_Delimiter;
|
|
PreviousRotation = 0;
|
|
PreviousRefAxis = 0;
|
|
iOriginShift = 0;
|
|
SignOriginShift = 0;
|
|
|
|
pos_hsym = 0;
|
|
|
|
do {
|
|
if (*hsym == '_' || *hsym == '.' || *hsym == '\t' || *hsym == '\0')
|
|
c = ' ';
|
|
else
|
|
c = *hsym;
|
|
|
|
pos_hsym++;
|
|
|
|
if (LatticeInfo == NULL) {
|
|
if (Centric == 0 && c == '-') {
|
|
if (AddInversion2ListSeitzMx(SgInfo) < 0)
|
|
return pos_hsym;
|
|
Centric = 1;
|
|
} else if (c != ' ') {
|
|
c = toupper(c);
|
|
|
|
switch (c) {
|
|
case 'P':
|
|
LatticeInfo = LI_P;
|
|
break;
|
|
case 'A':
|
|
LatticeInfo = LI_A;
|
|
break;
|
|
case 'B':
|
|
LatticeInfo = LI_B;
|
|
break;
|
|
case 'C':
|
|
LatticeInfo = LI_C;
|
|
break;
|
|
case 'I':
|
|
LatticeInfo = LI_I;
|
|
break;
|
|
case 'R':
|
|
LatticeInfo = LI_R;
|
|
break;
|
|
case 'S':
|
|
LatticeInfo = LI_S;
|
|
break;
|
|
case 'T':
|
|
LatticeInfo = LI_T;
|
|
break;
|
|
case 'F':
|
|
LatticeInfo = LI_F;
|
|
break;
|
|
default:
|
|
SetSgError("Error: Illegal lattice code");
|
|
return pos_hsym;
|
|
}
|
|
|
|
if (AddLatticeTr2ListSeitzMx(SgInfo, LatticeInfo) < 0)
|
|
return pos_hsym;
|
|
}
|
|
} else if (FieldType != FT_OriginShift) {
|
|
c = tolower(c);
|
|
if (c == 'q')
|
|
c = '\'';
|
|
else if (c == '+')
|
|
c = '"';
|
|
|
|
PreviousFT = FieldType;
|
|
digit = rotation = refaxis = dircode = 0;
|
|
translation = NULL;
|
|
|
|
ht = HallTranslations;
|
|
|
|
while (*ht) {
|
|
if (c == *ht) {
|
|
translation = ht;
|
|
FieldType = FT_Translation;
|
|
break;
|
|
}
|
|
ht += 4;
|
|
}
|
|
|
|
if (translation == NULL) {
|
|
switch (c) {
|
|
case ' ':
|
|
FieldType = FT_Delimiter;
|
|
break;
|
|
|
|
case '-':
|
|
FieldType = FT_Improper;
|
|
break;
|
|
|
|
case '1':
|
|
digit = 1;
|
|
FieldType = FT_Digit;
|
|
break;
|
|
case '2':
|
|
digit = 2;
|
|
FieldType = FT_Digit;
|
|
break;
|
|
case '3':
|
|
digit = 3;
|
|
FieldType = FT_Digit;
|
|
break;
|
|
case '4':
|
|
digit = 4;
|
|
FieldType = FT_Digit;
|
|
break;
|
|
case '5':
|
|
digit = 5;
|
|
FieldType = FT_Digit;
|
|
break;
|
|
case '6':
|
|
digit = 6;
|
|
FieldType = FT_Digit;
|
|
break;
|
|
|
|
case 'x':
|
|
case 'y':
|
|
case 'z':
|
|
refaxis = c;
|
|
FieldType = FT_RefAxis;
|
|
break;
|
|
|
|
case '"':
|
|
case '\'':
|
|
case '*':
|
|
dircode = c;
|
|
FieldType = FT_DirCode;
|
|
break;
|
|
|
|
case '(':
|
|
FieldType = FT_OriginShift;
|
|
break;
|
|
|
|
default:
|
|
SetSgError("Error: Illegal character in Hall symbol");
|
|
return pos_hsym;
|
|
}
|
|
|
|
if (FieldType == FT_Digit) {
|
|
if (ClearHG == 0
|
|
&& HG.Rotation > digit && HG.Screw == 0 && HG.DirCode == 0) {
|
|
HG.Screw = digit;
|
|
FieldType = FT_Translation;
|
|
} else if (digit == 5) {
|
|
SetSgError("Error: Illegal 5-fold rotation");
|
|
return pos_hsym;
|
|
} else {
|
|
rotation = digit;
|
|
FieldType = FT_Rotation;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ClearHG == 0
|
|
&& (FieldType == FT_Delimiter
|
|
|| FieldType == FT_OriginShift
|
|
|| FieldType < PreviousFT
|
|
|| (FieldType == PreviousFT && FieldType != FT_Translation))
|
|
&& !(FieldType == FT_RefAxis && HG.RefAxis == 0
|
|
&& PreviousFT == FT_DirCode)) {
|
|
if (HG.RefAxis == 0) {
|
|
if (nHG == 0)
|
|
HG.RefAxis = 'z';
|
|
else {
|
|
if (HG.Rotation == 2) {
|
|
if (PreviousRotation == 2 || PreviousRotation == 4)
|
|
HG.RefAxis = 'x';
|
|
else if (PreviousRotation == 3 || PreviousRotation == 6) {
|
|
HG.RefAxis = PreviousRefAxis;
|
|
if (HG.DirCode == 0)
|
|
HG.DirCode = '\'';
|
|
}
|
|
} else if (HG.Rotation == 3) {
|
|
if (HG.DirCode == 0)
|
|
HG.DirCode = '*';
|
|
}
|
|
}
|
|
}
|
|
|
|
PreviousRefAxis = HG.RefAxis;
|
|
PreviousRotation = HG.Rotation;
|
|
|
|
if (LookupRotMx(&HG) == 0) {
|
|
SetSgError
|
|
("Error: Illegal generator or need explicit axis symbol");
|
|
return pos_hsym - 1;
|
|
}
|
|
|
|
if (HG.Screw) {
|
|
switch (HG.RefAxis) {
|
|
case 'x':
|
|
i = 0;
|
|
break;
|
|
case 'y':
|
|
i = 1;
|
|
break;
|
|
case 'z':
|
|
i = 2;
|
|
break;
|
|
default:
|
|
i = -1;
|
|
break;
|
|
}
|
|
|
|
if (HG.DirCode != 0 || i < 0) {
|
|
SetSgError("Error: Screw for non-principal direction");
|
|
return pos_hsym - 1;
|
|
}
|
|
|
|
HG.SeitzMx.s.T[i] += STBF * HG.Screw / HG.Rotation;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
HG.SeitzMx.s.T[i] %= STBF;
|
|
|
|
if (Add2ListSeitzMx(SgInfo, &HG.SeitzMx) < 0)
|
|
return pos_hsym - 1;
|
|
|
|
if (SgInfo->StatusLatticeTr == -1) {
|
|
if (AddLatticeTr2ListSeitzMx(SgInfo, SgInfo->LatticeInfo) < 0)
|
|
return pos_hsym - 1;
|
|
}
|
|
|
|
nHG++;
|
|
ClearHG = 1;
|
|
}
|
|
|
|
if (FieldType != FT_Delimiter && FieldType != FT_OriginShift) {
|
|
if (ClearHG) {
|
|
HG.Improper = 0;
|
|
HG.Rotation = 1;
|
|
HG.RefAxis = 0;
|
|
HG.DirCode = 0;
|
|
HG.Screw = 0;
|
|
for (i = 0; i < 12; i++)
|
|
HG.SeitzMx.a[i] = 0;
|
|
|
|
ClearHG = 0;
|
|
}
|
|
|
|
switch (FieldType) {
|
|
case FT_Improper:
|
|
HG.Improper = 1;
|
|
break;
|
|
case FT_Rotation:
|
|
HG.Rotation = rotation;
|
|
break;
|
|
case FT_RefAxis:
|
|
HG.RefAxis = refaxis;
|
|
break;
|
|
case FT_DirCode:
|
|
HG.DirCode = dircode;
|
|
break;
|
|
case FT_Translation:
|
|
if (translation != NULL) {
|
|
for (i = 0; i < 3; i++)
|
|
HG.SeitzMx.s.T[i] += *(++translation);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} else { /* FieldType == FT_OriginShift */
|
|
|
|
if (iOriginShift > 3) {
|
|
SetSgError(Err_Too_ori_shi_val);
|
|
return pos_hsym;
|
|
}
|
|
|
|
if (*hsym == '\0')
|
|
c = ')';
|
|
|
|
digit = -1;
|
|
|
|
switch (c) {
|
|
case ' ':
|
|
break;
|
|
|
|
case ')':
|
|
if (iOriginShift != 3) {
|
|
SetSgError("Error: Missing origin shift values");
|
|
return pos_hsym;
|
|
}
|
|
iOriginShift++;
|
|
FieldType = FT_Delimiter;
|
|
break;
|
|
|
|
case '-':
|
|
if (SignOriginShift != 0) {
|
|
SetSgError(Err_Ill_ori_shi_val);
|
|
return pos_hsym;
|
|
}
|
|
SignOriginShift = 1;
|
|
break;
|
|
|
|
case '0':
|
|
digit = 0;
|
|
break;
|
|
case '1':
|
|
digit = 1;
|
|
break;
|
|
case '2':
|
|
digit = 2;
|
|
break;
|
|
case '3':
|
|
digit = 3;
|
|
break;
|
|
case '4':
|
|
digit = 4;
|
|
break;
|
|
case '5':
|
|
digit = 5;
|
|
break;
|
|
case '6':
|
|
digit = 6;
|
|
break;
|
|
|
|
default:
|
|
SetSgError(Err_Ill_ori_shi_val);
|
|
return pos_hsym;
|
|
}
|
|
|
|
if (digit >= 0) {
|
|
if (iOriginShift >= 3) {
|
|
SetSgError(Err_Too_ori_shi_val);
|
|
return pos_hsym;
|
|
}
|
|
if (SignOriginShift)
|
|
digit *= -1;
|
|
SignOriginShift = 0;
|
|
SgInfo->OriginShift[iOriginShift++] = digit;
|
|
}
|
|
}
|
|
}
|
|
while (*hsym++ != '\0');
|
|
|
|
if (LatticeInfo == NULL) {
|
|
SetSgError("Error: Lattice type not specified");
|
|
return pos_hsym;
|
|
}
|
|
|
|
return pos_hsym;
|
|
}
|
|
|
|
|
|
static const char *PrintSgLabel(const char *lbl, int space, int *n,
|
|
FILE * fpout)
|
|
{
|
|
while (*lbl && *lbl != ' ') {
|
|
if (*lbl == '_') {
|
|
if (space) {
|
|
putc(space, fpout);
|
|
if (n)
|
|
(*n)++;
|
|
}
|
|
} else {
|
|
putc(*lbl, fpout);
|
|
if (n)
|
|
(*n)++;
|
|
}
|
|
|
|
lbl++;
|
|
}
|
|
|
|
return lbl;
|
|
}
|
|
|
|
|
|
int PrintFullHM_SgName(const T_TabSgName * tsgn, int space, FILE * fpout)
|
|
{
|
|
int n;
|
|
const char *lbl;
|
|
|
|
|
|
lbl = tsgn->SgLabels;
|
|
|
|
if (tsgn->SgNumber >= 3 && tsgn->SgNumber < 16)
|
|
while (*lbl)
|
|
if (*lbl++ == '=')
|
|
break;
|
|
|
|
SkipWhite(lbl);
|
|
|
|
n = 0;
|
|
|
|
PrintSgLabel(lbl, space, &n, fpout);
|
|
|
|
lbl = tsgn->Extension;
|
|
|
|
if (*lbl && strchr("12HhRr", *lbl)) {
|
|
putc(':', fpout);
|
|
putc(*lbl, fpout);
|
|
n += 2;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
void PrintTabSgNameEntry(const T_TabSgName * tsgn, int Style, int space,
|
|
FILE * fpout)
|
|
{
|
|
int n;
|
|
const char *lbl, *SfSymbol;
|
|
|
|
|
|
if (Style)
|
|
n = fprintf(fpout, "%3d", tsgn->SgNumber);
|
|
else
|
|
n = fprintf(fpout, "%d", tsgn->SgNumber);
|
|
|
|
if (tsgn->Extension[0])
|
|
n += fprintf(fpout, ":%s", tsgn->Extension);
|
|
|
|
if (Style)
|
|
while (n < 9) {
|
|
putc(' ', fpout);
|
|
n++;
|
|
}
|
|
|
|
putc(' ', fpout);
|
|
n++;
|
|
putc(' ', fpout);
|
|
n++;
|
|
|
|
if (tsgn->SgNumber >= 1 && tsgn->SgNumber <= 230)
|
|
SfSymbol = SchoenfliesSymbols[tsgn->SgNumber];
|
|
else
|
|
SfSymbol = "";
|
|
|
|
n += fprintf(fpout, "%s", SfSymbol);
|
|
|
|
if (Style)
|
|
while (n < 23) {
|
|
putc(' ', fpout);
|
|
n++;
|
|
}
|
|
|
|
putc(' ', fpout);
|
|
n++;
|
|
putc(' ', fpout);
|
|
n++;
|
|
|
|
if (tsgn->SgNumber >= 3 && tsgn->SgNumber < 16) {
|
|
lbl = PrintSgLabel(tsgn->SgLabels, space, &n, fpout);
|
|
|
|
if (tsgn->Extension[0])
|
|
n += fprintf(fpout, ":%s", tsgn->Extension);
|
|
|
|
putc(' ', fpout);
|
|
putc('=', fpout);
|
|
putc(' ', fpout);
|
|
n += 3;
|
|
|
|
n += PrintFullHM_SgName(tsgn, space, fpout);
|
|
|
|
while (*lbl)
|
|
if (*lbl++ == '=')
|
|
break;
|
|
while (*lbl)
|
|
if (*lbl++ == '=')
|
|
break;
|
|
SkipWhite(lbl);
|
|
|
|
if (*lbl) {
|
|
putc(' ', fpout);
|
|
putc('=', fpout);
|
|
putc(' ', fpout);
|
|
n += 3;
|
|
|
|
PrintSgLabel(lbl, space, &n, fpout);
|
|
}
|
|
} else
|
|
n += PrintFullHM_SgName(tsgn, space, fpout);
|
|
|
|
if (Style)
|
|
while (n < 51) {
|
|
putc(' ', fpout);
|
|
n++;
|
|
}
|
|
|
|
putc(' ', fpout);
|
|
putc(' ', fpout);
|
|
|
|
fprintf(fpout, "%s", tsgn->HallSymbol);
|
|
}
|
|
|
|
|
|
static int FindGCD2(int ri, int rj)
|
|
{
|
|
int rk;
|
|
|
|
|
|
if (ri < 0)
|
|
ri = -ri;
|
|
|
|
if (rj) {
|
|
for (;;) {
|
|
rk = ri % rj;
|
|
if (rk == 0) {
|
|
ri = rj;
|
|
break;
|
|
}
|
|
ri = rj % rk;
|
|
if (ri == 0) {
|
|
ri = rk;
|
|
break;
|
|
}
|
|
rj = rk % ri;
|
|
if (rj == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ri < 0)
|
|
ri = -ri;
|
|
}
|
|
|
|
return ri;
|
|
}
|
|
|
|
|
|
static void SimplifyFraction(int nume, int deno, int *o_nume, int *o_deno)
|
|
{
|
|
int gcd = FindGCD2(nume, deno);
|
|
if (gcd) {
|
|
*o_nume = nume / gcd;
|
|
*o_deno = deno / gcd;
|
|
|
|
if (*o_deno < 0) {
|
|
*o_nume *= -1;
|
|
*o_deno *= -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const char *FormatFraction(int nume, int deno, int Decimal,
|
|
char *Buffer, int SizeBuffer)
|
|
{
|
|
int n, d;
|
|
char *cp, *cpp;
|
|
static char StaticBuffer[40];
|
|
|
|
|
|
if (NULL == Buffer) {
|
|
Buffer = StaticBuffer;
|
|
SizeBuffer = sizeof StaticBuffer / sizeof(*StaticBuffer);
|
|
}
|
|
|
|
Buffer[SizeBuffer - 1] = '\0';
|
|
|
|
if (nume == 0) {
|
|
Buffer[0] = '0';
|
|
Buffer[1] = '\0';
|
|
}
|
|
if (Decimal) {
|
|
sprintf(Buffer, "%.6g", (double) nume / deno);
|
|
|
|
cp = Buffer;
|
|
if (*cp == '-')
|
|
cp++;
|
|
if (*cp == '0') {
|
|
cpp = cp + 1;
|
|
while (*cp)
|
|
*cp++ = *cpp++;
|
|
}
|
|
} else {
|
|
SimplifyFraction(nume, deno, &n, &d);
|
|
|
|
if (d == 1)
|
|
sprintf(Buffer, "%d", n);
|
|
else
|
|
sprintf(Buffer, "%d/%d", n, d);
|
|
}
|
|
|
|
if (Buffer[SizeBuffer - 1] != '\0') {
|
|
Buffer[SizeBuffer - 1] = '\0';
|
|
SetSgError("Internal Error: FormatFraction(): Buffer too small");
|
|
return NULL;
|
|
}
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
|
|
const char *RTMx2XYZ(const T_RTMx * RTMx, int FacRo, int FacTr,
|
|
int Decimal, int TrFirst, int Low,
|
|
const char *Seperator,
|
|
char *BufferXYZ, int SizeBufferXYZ)
|
|
{
|
|
static const char *UpperXYZ = "XYZ";
|
|
static const char *LowerXYZ = "xyz";
|
|
|
|
int i, j, p, iRo, iTr;
|
|
char *xyz, buf_tr[32];
|
|
const char *sep, *LetterXYZ, *ro, *tr;
|
|
|
|
static char StaticBufferXYZ[80];
|
|
|
|
|
|
if (NULL == BufferXYZ) {
|
|
BufferXYZ = StaticBufferXYZ;
|
|
SizeBufferXYZ = sizeof StaticBufferXYZ / sizeof(*StaticBufferXYZ);
|
|
}
|
|
|
|
BufferXYZ[SizeBufferXYZ - 1] = '\0';
|
|
|
|
if (Low)
|
|
LetterXYZ = LowerXYZ;
|
|
else
|
|
LetterXYZ = UpperXYZ;
|
|
|
|
if (Seperator == NULL)
|
|
Seperator = ",";
|
|
|
|
xyz = BufferXYZ;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (i != 0)
|
|
for (sep = Seperator; *sep; sep++)
|
|
*xyz++ = *sep;
|
|
|
|
iTr = iModPositive(RTMx->s.T[i], FacTr);
|
|
if (iTr > FacTr / 2)
|
|
iTr -= FacTr;
|
|
|
|
tr = FormatFraction(iTr, FacTr, Decimal,
|
|
buf_tr, sizeof buf_tr / sizeof(*buf_tr));
|
|
if (tr == NULL)
|
|
return NULL;
|
|
|
|
p = 0;
|
|
|
|
if (TrFirst && iTr) {
|
|
if (*tr)
|
|
p = 1;
|
|
while (*tr)
|
|
*xyz++ = *tr++;
|
|
}
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
iRo = RTMx->s.R[i * 3 + j];
|
|
if (iRo) {
|
|
ro = FormatFraction(iRo, FacRo, Decimal, NULL, 0);
|
|
if (ro == NULL)
|
|
return NULL;
|
|
|
|
if (*ro == '-')
|
|
*xyz++ = *ro++;
|
|
else if (*ro && p)
|
|
*xyz++ = '+';
|
|
|
|
if (ro[0] != '1' || ro[1] != '\0') {
|
|
while (*ro)
|
|
*xyz++ = *ro++;
|
|
*xyz++ = '*';
|
|
}
|
|
|
|
*xyz++ = LetterXYZ[j];
|
|
|
|
p = 1;
|
|
}
|
|
}
|
|
|
|
if (!TrFirst && iTr) {
|
|
if (*tr && *tr != '-' && p)
|
|
*xyz++ = '+';
|
|
|
|
while (*tr)
|
|
*xyz++ = *tr++;
|
|
}
|
|
}
|
|
|
|
*xyz = '\0';
|
|
|
|
if (BufferXYZ[SizeBufferXYZ - 1] != '\0') {
|
|
BufferXYZ[SizeBufferXYZ - 1] = '\0';
|
|
SetSgError("Internal Error: RTMx2XYZ(): BufferXYZ too small");
|
|
return NULL;
|
|
}
|
|
|
|
return BufferXYZ;
|
|
}
|
|
|
|
|
|
void PrintMapleRTMx(const T_RTMx * RTMx, int FacRo, int FacTr,
|
|
const char *Label, FILE * fpout)
|
|
{
|
|
int i, j, nt;
|
|
const int *r, *t;
|
|
const char *ff;
|
|
|
|
|
|
if (Label)
|
|
fprintf(fpout, "%s", Label);
|
|
|
|
fprintf(fpout, " := matrix(4,4, [");
|
|
|
|
r = RTMx->s.R;
|
|
t = RTMx->s.T;
|
|
|
|
for (i = 0; i < 3; i++, t++) {
|
|
putc(' ', fpout);
|
|
|
|
for (j = 0; j < 3; j++, r++) {
|
|
ff = FormatFraction(*r, FacRo, 0, NULL, 0);
|
|
if (ff == NULL)
|
|
return;
|
|
|
|
fprintf(fpout, "%s,", ff);
|
|
}
|
|
|
|
nt = iModPositive(*t, FacTr);
|
|
if (nt > FacTr / 2)
|
|
nt -= FacTr;
|
|
|
|
ff = FormatFraction(nt, FacTr, 0, NULL, 0);
|
|
if (ff == NULL)
|
|
return;
|
|
|
|
fprintf(fpout, "%s,", ff);
|
|
}
|
|
|
|
fprintf(fpout, " 0,0,0,1]);\n");
|
|
}
|
|
|
|
|
|
static void PrintSeitzMx(const T_RTMx * SMx, FILE * fpout)
|
|
{
|
|
int i, nt;
|
|
const char *ff;
|
|
const int *r, *t;
|
|
|
|
|
|
r = SMx->s.R;
|
|
t = SMx->s.T;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
fprintf(fpout, " %2d", *r++);
|
|
fprintf(fpout, " %2d", *r++);
|
|
fprintf(fpout, " %2d", *r++);
|
|
|
|
nt = iModPositive(*t++, STBF);
|
|
if (nt > STBF / 2)
|
|
nt -= STBF;
|
|
|
|
ff = FormatFraction(nt, STBF, 0, NULL, 0);
|
|
if (ff == NULL)
|
|
return;
|
|
|
|
fprintf(fpout, " %6s\n", ff);
|
|
}
|
|
|
|
putc('\n', fpout);
|
|
}
|
|
|
|
|
|
void ListSgInfo(const T_SgInfo * SgInfo, int F_XYZ, int F_Verbose,
|
|
FILE * fpout)
|
|
{
|
|
int iList, i_si_v;
|
|
char buf[8];
|
|
const char *xyz;
|
|
const T_RTMx *lsmx;
|
|
T_RotMxInfo *rmxi, RotMxInfo;
|
|
|
|
|
|
iList = PG_Index(SgInfo->PointGroup);
|
|
|
|
fprintf(fpout, "Point Group %s\n", PG_Names[iList]);
|
|
fprintf(fpout, "Laue Group %s\n",
|
|
PG_Names[PG_Index(LG_Code_of_PG_Index[iList])]);
|
|
|
|
fprintf(fpout, "%s\n", XS_Name[SgInfo->XtalSystem]);
|
|
|
|
if (SgInfo->UniqueRefAxis != 0 || SgInfo->UniqueDirCode != 0) {
|
|
fprintf(fpout, "Unique Axis ");
|
|
if (SgInfo->UniqueRefAxis != 0 && SgInfo->UniqueRefAxis != 'o')
|
|
fprintf(fpout, "%c", SgInfo->UniqueRefAxis);
|
|
if (SgInfo->UniqueDirCode != 0 && SgInfo->UniqueDirCode != '=')
|
|
fprintf(fpout, "%c", SgInfo->UniqueDirCode);
|
|
fprintf(fpout, "\n");
|
|
}
|
|
|
|
if (SgInfo->ExtraInfo != EI_Unknown)
|
|
fprintf(fpout, "%s\n", EI_Name[SgInfo->ExtraInfo]);
|
|
|
|
if (SgInfo->InversionOffOrigin)
|
|
fprintf(fpout, "Note: Inversion operation off origin\n");
|
|
|
|
putc('\n', fpout);
|
|
|
|
fprintf(fpout, "Order %3d\n", SgInfo->OrderL);
|
|
fprintf(fpout, "Order P %3d\n", SgInfo->OrderP);
|
|
putc('\n', fpout);
|
|
|
|
if (SgInfo->n_si_Vector >= 0) {
|
|
fprintf(fpout, "s.i.Vector Modulus\n");
|
|
for (i_si_v = 0; i_si_v < SgInfo->n_si_Vector; i_si_v++)
|
|
fprintf(fpout, " %2d %2d %2d %d\n",
|
|
SgInfo->si_Vector[i_si_v * 3 + 0],
|
|
SgInfo->si_Vector[i_si_v * 3 + 1],
|
|
SgInfo->si_Vector[i_si_v * 3 + 2],
|
|
SgInfo->si_Modulus[i_si_v]);
|
|
putc('\n', fpout);
|
|
}
|
|
|
|
if (F_XYZ || F_Verbose) {
|
|
fprintf(fpout, "#List %3d\n", SgInfo->nList);
|
|
putc('\n', fpout);
|
|
|
|
lsmx = SgInfo->ListSeitzMx;
|
|
rmxi = SgInfo->ListRotMxInfo;
|
|
|
|
if (rmxi == NULL)
|
|
rmxi = &RotMxInfo;
|
|
|
|
for (iList = 0; iList < SgInfo->nList; iList++, lsmx++) {
|
|
if (rmxi == &RotMxInfo) {
|
|
if (GetRotMxInfo(lsmx->s.R, &RotMxInfo) == 0) {
|
|
SetSgError("Error: Illegal SeitzMx in list");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (F_Verbose) {
|
|
sprintf(buf, "(%d)", iList + 1);
|
|
fprintf(fpout, "%-4s", buf);
|
|
|
|
fprintf(fpout, " %2d", rmxi->Order);
|
|
if (rmxi->Inverse)
|
|
fprintf(fpout, "^-1");
|
|
else
|
|
fprintf(fpout, " ");
|
|
|
|
fprintf(fpout, " [%2d %2d %2d]",
|
|
rmxi->EigenVector[0],
|
|
rmxi->EigenVector[1], rmxi->EigenVector[2]);
|
|
|
|
if (rmxi->RefAxis)
|
|
fprintf(fpout, " '%c'", rmxi->RefAxis);
|
|
else
|
|
fprintf(fpout, " ");
|
|
if (rmxi->DirCode)
|
|
fprintf(fpout, " '%c'", rmxi->DirCode);
|
|
else
|
|
fprintf(fpout, " ");
|
|
|
|
fprintf(fpout, " ");
|
|
}
|
|
|
|
xyz = RTMx2XYZ(lsmx, 1, STBF, 0, 0, 1, ", ", NULL, 0);
|
|
if (xyz)
|
|
fprintf(fpout, "%s", xyz);
|
|
|
|
putc('\n', fpout);
|
|
|
|
if (xyz == NULL)
|
|
return;
|
|
|
|
if (F_Verbose)
|
|
PrintSeitzMx(lsmx, fpout);
|
|
|
|
if (rmxi != &RotMxInfo)
|
|
rmxi++;
|
|
}
|
|
|
|
if (iList && F_Verbose == 0)
|
|
putc('\n', fpout);
|
|
}
|
|
}
|