Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions src/cairo-utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include "cairo-utils.hpp"

#include <cairo/cairo.h>
#include <inttypes.h>
#include <math.h>
#include <assert.h>

#include <string>

#include "attitude-utils.hpp"
#include "decimal.hpp"
#include "star-utils.hpp"

namespace lost {

/// Convert a colored Cairo image surface into a row-major array of grayscale pixels.
/// Result is allocated with new[]
unsigned char *SurfaceToGrayscaleImage(cairo_surface_t *cairoSurface) {
int width, height;
unsigned char *result;
uint32_t *cairoImage, pixel;

if (cairo_image_surface_get_format(cairoSurface) != CAIRO_FORMAT_ARGB32 &&
cairo_image_surface_get_format(cairoSurface) != CAIRO_FORMAT_RGB24) {
puts("Can't convert weird image formats to grayscale.");
return NULL;
}

width = cairo_image_surface_get_width(cairoSurface);
height = cairo_image_surface_get_height(cairoSurface);

result = new unsigned char[width*height];
cairoImage = (uint32_t *)cairo_image_surface_get_data(cairoSurface);

for (int i = 0; i < height * width; i++) {
pixel = cairoImage[i];
// use "luminosity" method of grayscaling
result[i] = round(
(pixel>>16 &0xFF) *0.21 +
(pixel>>8 &0xFF) *0.71 +
(pixel &0xFF) *0.07);
}

return result;
}

cairo_surface_t *GrayscaleImageToSurface(const unsigned char *image,
const int width, const int height) {
// cairo's 8-bit type isn't BW, it's an alpha channel only, which would look a bit weird lol
cairo_surface_t *result = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
uint32_t *resultData = (uint32_t *)cairo_image_surface_get_data(result);
// hopefully unnecessary
cairo_surface_flush(result);
for (long i = 0; i < width * height; i++) {
// equal r, g, and b components
resultData[i] = (image[i] << 16) + (image[i] << 8) + (image[i]);
}
cairo_surface_mark_dirty(result);
return result;
}

/**
* Plot information about an image onto the image using Cairo.
* Puts a box around each centroid, writes the attitude in the top left, etc.
* @param red,green,blue The color to use when annotating the image. 0 represents none of that color, 1 represents that color in full.
* @param alpha The transparency of annotations. 0 is completely transparent, 1 is completely opaque.
* @param rawStarIndexes If true, print the catalog index. This is in contrast with the default behavior, which is to print the name of the catalog star.
*/
void SurfacePlot(std::string description,
cairo_surface_t *cairoSurface,
const Stars &stars,
const StarIdentifiers *starIds,
const Catalog *catalog,
const Attitude *attitude,
double red,
double green,
double blue,
double alpha,
// if true, don't use catalog name
bool rawStarIndexes) {
cairo_t *cairoCtx;
std::string metadata = description + " ";

cairoCtx = cairo_create(cairoSurface);
cairo_set_source_rgba(cairoCtx, red, green, blue, alpha);
cairo_set_line_width(cairoCtx, 1.0);
cairo_set_antialias(cairoCtx, CAIRO_ANTIALIAS_NONE);
cairo_font_options_t *cairoFontOptions = cairo_font_options_create();
cairo_font_options_set_antialias(cairoFontOptions, CAIRO_ANTIALIAS_NONE);
cairo_set_font_options(cairoCtx, cairoFontOptions);
cairo_text_extents_t cairoTextExtents;
cairo_text_extents(cairoCtx, "1234567890", &cairoTextExtents);
decimal textHeight = cairoTextExtents.height;

for (const Star &centroid : stars) {
// plot the box around the star
if (centroid.radiusX > DECIMAL(0.0)) {
decimal radiusX = centroid.radiusX;
decimal radiusY = centroid.radiusY > DECIMAL(0.0) ?
centroid.radiusY : radiusX;

// Rectangles should be entirely /outside/ the radius of the star, so the star is
// fully visible.
cairo_rectangle(cairoCtx,
centroid.position.x - radiusX,
centroid.position.y - radiusY,
radiusX * 2,
radiusY * 2);
cairo_stroke(cairoCtx);
} else {
cairo_rectangle(cairoCtx,
DECIMAL_FLOOR(centroid.position.x),
DECIMAL_FLOOR(centroid.position.y),
1, 1);
cairo_fill(cairoCtx);
}
}

metadata += std::to_string(stars.size()) + " centroids ";

if (starIds != NULL) {
assert(catalog != NULL);

for (const StarIdentifier &starId : *starIds) {
const Star &centroid = stars[starId.starIndex];
cairo_move_to(cairoCtx,

centroid.radiusX > DECIMAL(0.0)
? centroid.position.x + centroid.radiusX + 3
: centroid.position.x + 8,

centroid.radiusY > DECIMAL(0.0)
? centroid.position.y - centroid.radiusY + textHeight
: centroid.position.y + 10);

int plotName = rawStarIndexes ? starId.catalogIndex : (*catalog)[starId.catalogIndex].name;
cairo_show_text(cairoCtx, std::to_string(plotName).c_str());
}
metadata += std::to_string(starIds->size()) + " identified ";
}

if (attitude != NULL) {
EulerAngles spherical = attitude->ToSpherical();
metadata +=
"RA: " + std::to_string(RadToDeg(spherical.ra)) + " " +
"DE: " + std::to_string(RadToDeg(spherical.de)) + " " +
"Roll: " + std::to_string(RadToDeg(spherical.roll)) + " ";
}

// plot metadata
cairo_move_to(cairoCtx, 3, 3 + textHeight);
cairo_show_text(cairoCtx, metadata.c_str());

cairo_font_options_destroy(cairoFontOptions);
cairo_destroy(cairoCtx);
}

} // namespace lost
44 changes: 44 additions & 0 deletions src/cairo-utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef CAIRO_UTILS_H
#define CAIRO_UTILS_H

#include <cairo/cairo.h>

#include <string>

#include "star-utils.hpp"
#include "attitude-utils.hpp"

namespace lost {

/// An 8-bit grayscale 2d image
class Image {
public:
/**
* The raw pixel data in the image.
* This is an array of pixels, of length width*height. Each pixel is a single byte. A zero byte is pure black, and a 255 byte is pure white. Support for pixel resolution greater than 8 bits may be added in the future.
*/
unsigned char *image;

int width;
int height;
};

// Convert a cairo surface to array of grayscale bytes
unsigned char *SurfaceToGrayscaleImage(cairo_surface_t *cairoSurface);
cairo_surface_t *GrayscaleImageToSurface(const unsigned char *, const int width, const int height);

void SurfacePlot(std::string description,
cairo_surface_t *cairoSurface,
const Stars &stars,
const StarIdentifiers *starIds,
const Catalog *catalog,
const Attitude *attitude,
double red,
double green,
double blue,
double alpha,
bool rawStarIndexes = false);

}

#endif
74 changes: 74 additions & 0 deletions src/databases-builder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "databases-builder.hpp"

#include <bitset>
#include <iostream>
#include <string>

#include "attitude-utils.hpp"
#include "databases.hpp"
#include "decimal.hpp"
#include "io-util.hpp"
#include "star-utils.hpp"

namespace lost {

SerializeContext serFromDbValues(const DatabaseOptions &values) {
return SerializeContext(values.swapIntegerEndianness, values.swapDecimalEndianness);
}

MultiDatabaseDescriptor GenerateDatabases(const Catalog &catalog, const DatabaseOptions &values) {
MultiDatabaseDescriptor dbEntries;

SerializeContext catalogSer = serFromDbValues(values);
// TODO decide why we have this inclMagnitude and inclName and if we should change that
SerializeCatalog(&catalogSer, catalog, false, true);
dbEntries.emplace_back(kCatalogMagicValue, catalogSer.buffer);

if (values.kvector) {
decimal minDistance = DegToRad(values.kvectorMinDistance);
decimal maxDistance = DegToRad(values.kvectorMaxDistance);
long numBins = values.kvectorNumDistanceBins;
SerializeContext ser = serFromDbValues(values);
SerializePairDistanceKVector(&ser, catalog, minDistance, maxDistance, numBins);
dbEntries.emplace_back(PairDistanceKVectorDatabase::kMagicValue, ser.buffer);
} else {
std::cerr << "No database builder selected -- no database generated." << std::endl;
exit(1);
}

return dbEntries;
}

/// Build a star database from the catalog and write it to the output path.
void DatabaseBuild(const DatabaseOptions &values) {
Catalog narrowedCatalog = NarrowCatalog(CatalogRead(), (int) (values.minMag * 100), values.maxStars, DegToRad(values.minSeparation));
std::cerr << "Narrowed catalog has " << narrowedCatalog.size() << " stars." << std::endl;

MultiDatabaseDescriptor dbEntries = GenerateDatabases(narrowedCatalog, values);
SerializeContext ser = serFromDbValues(values);

// Build the flags word. Currently the only flag indicates whether the
// database was built with single-precision (float) or double-precision decimals.
uint32_t dbFlags = 0;
dbFlags |= typeid(decimal) == typeid(float) ? MULTI_DB_FLOAT_FLAG : 0;

SerializeMultiDatabase(&ser, dbEntries, dbFlags);

std::cerr << "Generated database with " << ser.buffer.size() << " bytes" << std::endl;
std::cerr << "Database flagged with " << std::bitset<8*sizeof(dbFlags)>(dbFlags) << std::endl;

UserSpecifiedOutputStream pos = UserSpecifiedOutputStream(values.outputPath, true);
pos.Stream().write((char *) ser.buffer.data(), ser.buffer.size());
}

/// Print information about the camera in machine and human-readable form.
std::ostream &operator<<(std::ostream &os, const Camera &camera) {
os << "camera_focal_length " << camera.FocalLength() << std::endl
<< "camera_fov " << camera.Fov() << std::endl
<< "camera_resolution_x " << camera.XResolution() << std::endl
<< "camera_resolution_y " << camera.YResolution() << std::endl;
// TODO: principal point
return os;
}

} // namespace lost
36 changes: 36 additions & 0 deletions src/databases-builder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef DATABASES_BUILDER_H
#define DATABASES_BUILDER_H

#include <string>
#include <iostream>

#include "databases.hpp"
#include "camera.hpp"
#include "star-utils.hpp"
#include "decimal.hpp"

namespace lost {

/// Commannd line options when using the `database` command.
class DatabaseOptions {
public:
#define LOST_CLI_OPTION(name, type, prop, defaultVal, converter, defaultArg) \
type prop = defaultVal;
#include "database-options.hpp"
#undef LOST_CLI_OPTION
};

SerializeContext serFromDbValues(const DatabaseOptions &values);

/// Appropriately create descriptors for all requested databases according to command-line options.
/// @sa SerializeMultiDatabase
MultiDatabaseDescriptor GenerateDatabases(const Catalog &, const DatabaseOptions &values);

/// Build a star database from the catalog and write it to the output path.
void DatabaseBuild(const DatabaseOptions &values);

std::ostream &operator<<(std::ostream &, const Camera &);

}

#endif
Loading
Loading