#include "../search_star/search_star.h" #include #include // Note: FetchCatalogNames() must be called before this function is called. static bool display_nearbies (HDBC hdbc, HSTMT hstmt, double minRAhrs, double maxRAhrs, double minDecDegs, double maxDecDegs, double sourceX, double sourceY, double sourceZ, double maxLightYears, double minLightYears, long throwawayID = 0) { char buffer[512]; RETCODE retcode; struct RawPosition pos; const MAX_DISPLAYED = 100; struct { long ID; double distance; } systemArray[MAX_DISPLAYED + 1]; int numFound = 0, numActuallyFound = 0; long ownerID; SDWORD cbRA_hr, cbRA_min, cbRA_sec; SDWORD cbDec_deg, cbDec_arcmin, cbDec_arcsec; SDWORD cbDistance, cbOwnerID; retcode = SQLFreeStmt (hstmt, SQL_CLOSE); sprintf (buffer, "SELECT RA_hr, RA_min, RA_sec, Dec_deg, Dec_arcmin, " "Dec_arcsec, Distance, OwnerID FROM Positions"); retcode = SQLExecDirect (hstmt, (unsigned char *) buffer, SQL_NTS); if (retcode != SQL_SUCCESS) { puts ("
Internal error: Database query failed."); return false; } SQLBindCol(hstmt, 1, SQL_C_UTINYINT, &pos.RA_hr, 0, &cbRA_hr); SQLBindCol(hstmt, 2, SQL_C_UTINYINT, &pos.RA_min, 0, &cbRA_min); SQLBindCol(hstmt, 3, SQL_C_FLOAT, &pos.RA_sec, 0, &cbRA_sec); SQLBindCol(hstmt, 4, SQL_C_SHORT, &pos.Dec_deg, 0, &cbDec_deg); SQLBindCol(hstmt, 5, SQL_C_UTINYINT, &pos.Dec_arcmin, 0, &cbDec_arcmin); SQLBindCol(hstmt, 6, SQL_C_FLOAT, &pos.Dec_arcsec, 0, &cbDec_arcsec); SQLBindCol(hstmt, 7, SQL_C_DOUBLE, &pos.Distance, 0, &cbDistance); SQLBindCol(hstmt, 8, SQL_C_LONG, &ownerID, 0, &cbOwnerID); while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { double x, y, z; if (ownerID % 100 || ownerID == throwawayID) continue; // system coords only, no components pos.bRA = cbRA_hr != SQL_NULL_DATA; pos.bDec = cbDec_deg != SQL_NULL_DATA; pos.bDistance = cbDistance != SQL_NULL_DATA; if (!RDD2XYZ (&pos, x, y, z, true)) continue; double distance = sqrt ( (x-sourceX) * (x-sourceX) + (y-sourceY) * (y-sourceY) + (z-sourceZ) * (z-sourceZ) ); if (distance > maxLightYears || distance < minLightYears) continue; double RAHrs = 0.0, DecDegs = 0.0; if (pos.bRA) RAHrs = pos.RA_hr + pos.RA_min/60.0 + pos.RA_sec/3600.0; if (pos.bDec) { int dec_sign; if (pos.Dec_deg < 0) dec_sign = -1; else dec_sign = 1; DecDegs = pos.Dec_deg + pos.Dec_arcmin*dec_sign/60.0 + pos.Dec_arcsec*dec_sign/3600.0; } if (RAHrs < minRAhrs || RAHrs > maxRAhrs || DecDegs < minDecDegs || DecDegs > maxDecDegs) continue; // This system has passed our gauntlet, put it in the array if not full: for (register i = 0; i < numFound; ++i) { if (systemArray[i].distance > distance) { memmove (systemArray + i + 1, systemArray + i, sizeof systemArray[0] * (numFound - i)); systemArray[i].ID = ownerID; systemArray[i].distance = distance; break; } } if (i == numFound) { systemArray[i].ID = ownerID; systemArray[i].distance = distance; } ++ numFound; if (numFound > MAX_DISPLAYED) numFound = MAX_DISPLAYED; ++ numActuallyFound; } if (numActuallyFound > MAX_DISPLAYED) printf ("
%d stars were found.  Only the nearest %d will be displayed.\n
\n", numActuallyFound, MAX_DISPLAYED); if (numFound) { for (register i = 0; i < numFound; ++i) { char nameBuf[122]; FetchMainSystemName (hstmt, systemArray[i].ID, nameBuf); printf ("
%s: " "%g light-years", systemArray[i].ID, nameBuf, systemArray[i].distance); // Show spectral & luminosity class for system's primary component: RawSpectrum rs; if (FetchRawSpectrum (hstmt, systemArray[i].ID+1, rs) && rs.bSpectralClass) printf (", class %s %s", rs.SpectralClass, rs.bLuminosityClass ? rs.LuminosityClass : ""); printf ("\n"); } } else puts ("
No neighboring stars were found in the Internet Stellar Database."); return true; } static int sMinRAHour = 0, sMaxRAHour = 23; static int sMinRAMin = 0, sMaxRAMin = 59; static double sMinRASec = 0.0, sMaxRASec = 59.999; static int sMinDecDeg = -89, sMaxDecDeg = +89; static int sMinDecMin = 59, sMaxDecMin = 59; static double sMinDecSec = 59.999, sMaxDecSec = 59.999; static bool display_neighbors (HDBC hdbc, HSTMT hstmt, long ID, double minRAhrs, double maxRAhrs, double minDecDegs, double maxDecDegs, double maxLightYears, double minLightYears) { char buffer[512]; double sourceX, sourceY, sourceZ; struct RawPosition sourcePosition; if (!FetchRawPosition (hstmt, ID, &sourcePosition)) return false; if (!RDD2XYZ (&sourcePosition, sourceX, sourceY, sourceZ, true)) return false; FetchCatalogNames (hstmt); FetchMainSystemName (hstmt, ID, buffer); printf ("Content-type: text/html%c%c", 10, 10); puts (""); puts (""); puts (""); puts (""); puts ("ISDB neighbor search results"); puts (""); puts (""); if (minLightYears > 0.0) printf ("

Stars between %g and %g light-years from %s", minLightYears, maxLightYears, buffer); else printf ("

Stars within %g light-years of %s", maxLightYears, buffer); if (minRAhrs > 0.0 || maxRAhrs < 23.9999997) printf (", with Right Ascensions between %dh%dm%gs and %dh%dm%gs", sMinRAHour, sMinRAMin, sMinRASec, sMaxRAHour, sMaxRAMin, sMaxRASec); if (minDecDegs > -89.9999997 || maxDecDegs < 89.9999997) { printf (", "); if (minRAhrs > 0.0 || maxRAhrs < 23.9999997) printf ("and"); else printf ("with"); printf (" Declinations between %+d°%d'%g\" and %+d°%d'%g\"", sMinDecDeg, sMinDecMin, sMinDecSec, sMaxDecDeg, sMaxDecMin, sMaxDecSec); } printf (":

\n"); display_nearbies (hdbc, hstmt, minRAhrs, maxRAhrs, minDecDegs, maxDecDegs, sourceX, sourceY, sourceZ, maxLightYears, minLightYears, ID); DisposeCatalogNames(); puts ("\n"); return true; // return true even if display_nearbies fails. } int main() { HENV henv; HDBC hdbc; HSTMT hstmt; RETCODE retcode; int mainRetCode = -1; long systemID = 0; double minLightYears = 0.0; double maxLightYears = 15.0; double X = 0.0, Y = 0.0, Z = 0.0; double minRA, maxRA; // in decimal hours double minDec, maxDec; // in decimal degrees const char *szQueryString = getenv ("QUERY_STRING"); // const char *szQueryString = "ID=196100&ly=20"; // const char *szQueryString = "minRAHour=15&maxRAHour=16"; const char *szArg; if (!szQueryString) { puts ("Content-type: text/plain\n"); puts ("This CGI program must be passed a query string " "containing either an \"ID=###00\" clause,"); puts ("or \"X=###\", \"Y=###\", and \"Z=###\" clauses,"); puts ("or clauses for min. and max. RA and Dec components."); return -1; } ParseToList (szQueryString); szArg = QueryVariable::FindName ("ID"); if (!szArg || !szArg[0]) { bool foundAllOK = false; szArg = QueryVariable::FindName ("X"); if (szArg && szArg[0]) { X = atof(szArg); szArg = QueryVariable::FindName ("Y"); if (szArg && szArg[0]) { Y = atof(szArg); szArg = QueryVariable::FindName ("Z"); if (szArg && szArg[0]) { Z = atof(szArg); foundAllOK = true; } } } if (!foundAllOK) { /* puts ("Content-type: text/plain\n"); puts ("This CGI program must be passed a query string " "containing either an \"ID=###00\" clause,"); puts ("or \"X=###\", \"Y=###\", and \"Z=###\" clauses."); return -1; */ } } else if (!(systemID = atol(szArg)) || systemID % 100) { puts ("Content-type: text/plain\n"); puts ("Invalid \"ID=###\" clause. Must be a multiple of 100 greater than 0."); return -1; } szArg = QueryVariable::FindName ("ly"); if (szArg) { maxLightYears = atof (szArg); if (maxLightYears < 2.0) { puts ("Content-type: text/plain\n"); puts ("Search radius must be at least 2 light-years."); return -1; } } szArg = QueryVariable::FindName ("minLY"); if (szArg) { minLightYears = atof (szArg); if (minLightYears > maxLightYears) { puts ("Content-type: text/plain\n"); puts ("Minimum search radius cannot be greater than maximum search radius."); return -1; } } szArg = QueryVariable::FindName ("minRAHour"); if (szArg) { sMinRAHour = atoi (szArg); if (sMinRAHour < 0 || sMinRAHour > 23) { puts ("Content-type: text/plain\n"); puts ("Minimum right ascension hours must be between 0 and 23 inclusive."); return -1; } sMinRAMin = 0; sMinRASec = 0.0; } szArg = QueryVariable::FindName ("minRAMin"); if (szArg) { sMinRAMin = atoi (szArg); if (sMinRAMin < 0 || sMinRAMin > 59) { puts ("Content-type: text/plain\n"); puts ("Minimum right ascension minutes must be between 0 and 59 inclusive."); return -1; } sMinRASec = 0.0; } szArg = QueryVariable::FindName ("minRASec"); if (szArg) { sMinRASec = atof (szArg); if (sMinRASec < 0.0 || sMinRASec > 59.999999999) { puts ("Content-type: text/plain\n"); puts ("Minimum right ascension seconds must be >= 0 and < 60."); return -1; } } minRA = sMinRAHour + sMinRAMin/60.0 + sMinRASec/3600.0; szArg = QueryVariable::FindName ("maxRAHour"); if (szArg) { sMaxRAHour = atoi (szArg); if (sMaxRAHour < 0 || sMaxRAHour > 23) { puts ("Content-type: text/plain\n"); puts ("Maximum right ascension hours must be between 0 and 23 inclusive."); return -1; } sMaxRAMin = 0; sMaxRASec = 0.0; } szArg = QueryVariable::FindName ("maxRAMin"); if (szArg) { sMaxRAMin = atoi (szArg); if (sMaxRAMin < 0 || sMaxRAMin > 59) { puts ("Content-type: text/plain\n"); puts ("Maximum right ascension minutes must be between 0 and 59 inclusive."); return -1; } sMaxRASec = 0.0; } szArg = QueryVariable::FindName ("maxRASec"); if (szArg) { sMaxRASec = atof (szArg); if (sMaxRASec < 0.0 || sMaxRASec > 59.999999999) { puts ("Content-type: text/plain\n"); puts ("Maximum right ascension seconds must be >= 0 and < 60."); return -1; } } maxRA = sMaxRAHour + sMaxRAMin/60.0 + sMaxRASec/3600.0; if (minRA > maxRA) { puts ("Content-type: text/plain\n"); puts ("Minimum right ascension cannot be greater than maximum right ascension."); return -1; } szArg = QueryVariable::FindName ("minDecDeg"); if (szArg) { sMinDecDeg = atoi (szArg); if (sMinDecDeg < -89 || sMinDecDeg > +89) { puts ("Content-type: text/plain\n"); puts ("Minimum declination degrees must be between -89 and +89 inclusive."); return -1; } sMinDecMin = 0; sMinDecSec = 0.0; } szArg = QueryVariable::FindName ("minDecMin"); if (szArg) { sMinDecMin = atoi (szArg); if (sMinDecMin < 0 || sMinDecMin > 59) { puts ("Content-type: text/plain\n"); puts ("Minimum declination minutes must be between 0 and 59 inclusive."); return -1; } sMinDecSec = 0.0; } szArg = QueryVariable::FindName ("minDecSec"); if (szArg) { sMinDecSec = atof (szArg); if (sMinDecSec < 0.0 || sMinDecSec > 59.999999999) { puts ("Content-type: text/plain\n"); puts ("Minimum declination seconds must be >= 0 and < 60"); return -1; } } int dec_sign; if (sMinDecDeg < 0) dec_sign = -1; else dec_sign = 1; minDec = sMinDecDeg + sMinDecMin*dec_sign/60.0 + sMinDecSec*dec_sign/3600.0; szArg = QueryVariable::FindName ("maxDecDeg"); if (szArg) { sMaxDecDeg = atoi (szArg); if (sMaxDecDeg < -89 || sMaxDecDeg > +89) { puts ("Content-type: text/plain\n"); puts ("Maxmimum declination degrees must be between -89 and +89 inclusive."); return -1; } sMaxDecMin = 0; sMaxDecSec = 0.0; } szArg = QueryVariable::FindName ("maxDecMin"); if (szArg) { sMaxDecMin = atoi (szArg); if (sMaxDecMin < 0 || sMaxDecMin > 59) { puts ("Content-type: text/plain\n"); puts ("Maximum declination minutes must be between 0 and 59 inclusive."); return -1; } sMaxDecSec = 0.0; } szArg = QueryVariable::FindName ("maxDecSec"); if (szArg) { sMaxDecSec = atof (szArg); if (sMaxDecSec < 0.0 || sMaxDecSec > 59.999999999) { puts ("Content-type: text/plain\n"); puts ("Maximum declination seconds must be >= 0 and < 60"); return -1; } } if (sMaxDecDeg < 0) dec_sign = -1; else dec_sign = 1; maxDec = sMaxDecDeg + sMaxDecMin*dec_sign/60.0 + sMaxDecSec*dec_sign/3600.0; if (minDec > maxDec) { puts ("Content-type: text/plain\n"); puts ("Minimum declination cannot be greater than maximum declination."); return -1; } retcode = SQLAllocEnv(&henv); if (retcode == SQL_SUCCESS) { retcode = SQLAllocConnect(henv, &hdbc); if (retcode == SQL_SUCCESS) { SQLSetConnectOption(hdbc, SQL_LOGIN_TIMEOUT, 2); SQLSetConnectOption(hdbc, SQL_ACCESS_MODE, SQL_MODE_READ_ONLY); // Note: for the following statement to succeed, the system // running this code MUST have a System DSN of "ISDB" // configured to use the MS Access 97 driver with a "Database" // of C:\ISDB\ISDB.MDB in the ODBC32 Control Panel applet. retcode = SQLConnect(hdbc, (unsigned char *) "ISDB", SQL_NTS, (unsigned char *) "", 0, (unsigned char *) "", 0); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { retcode = SQLAllocStmt(hdbc, &hstmt); if (retcode == SQL_SUCCESS) { if (systemID) { if (display_neighbors (hdbc, hstmt, systemID, minRA, maxRA, minDec, maxDec, maxLightYears, minLightYears)) mainRetCode = 0; } else { FetchCatalogNames (hstmt); printf ("Content-type: text/html%c%c", 10, 10); puts (""); puts (""); puts (""); puts (""); puts ("ISDB near-coordinate search results"); puts (""); puts (""); if (minLightYears > 0.0) printf ("

Stars between %g and %g light-years " "from (%g, %g, %g)", minLightYears, maxLightYears, X, Y, Z); else printf ("

Stars within %g light-years " "of (%g, %g, %g)", maxLightYears, X, Y, Z); if (minRA > 0.0 || maxRA < 23.9999997) printf (", with Right Ascensions between %dh%dm%gs and %dh%dm%gs", sMinRAHour, sMinRAMin, sMinRASec, sMaxRAHour, sMaxRAMin, sMaxRASec); if (minDec > -89.9999997 || maxDec < 89.9999997) { printf (", "); if (minRA > 0.0 || maxRA < 23.9999997) printf ("and"); else printf ("with"); printf (" Declinations between %+d°%d'%g\" and %+d°%d'%g\"", sMinDecDeg, sMinDecMin, sMinDecSec, sMaxDecDeg, sMaxDecMin, sMaxDecSec); } printf (":

\n"); display_nearbies (hdbc, hstmt, minRA, maxRA, minDec, maxDec, X, Y, Z, maxLightYears, minLightYears); DisposeCatalogNames(); puts ("\n"); mainRetCode = 0; } SQLFreeStmt(hstmt, SQL_DROP); } SQLDisconnect(hdbc); } else { char szSqlState [20]; char szErrorMsg [SQL_MAX_MESSAGE_LENGTH]; SDWORD fNativeError; SWORD cbErrorMsg; printf ("Content-type: text/plain\n\n"); printf ("SQLConnect() failed!!\n"); retcode = SQLError (henv, hdbc, SQL_NULL_HSTMT, (UCHAR *) szSqlState, &fNativeError, (UCHAR *) szErrorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { printf ("SQLSTATE = '%s'\n", szSqlState); printf ("Error message = '%s'\n", szErrorMsg); } mainRetCode = 0; } SQLFreeConnect(hdbc); } SQLFreeEnv(henv); } if (mainRetCode) { printf ("Content-type: text/html%c%c", 10, 10); puts (""); puts (""); puts (""); puts (""); puts ("ISDB search results"); puts (""); puts (""); printf ("No star name matching ID %ld found.\n", systemID); puts ("\n"); } return mainRetCode; }