Commit 081b040e authored by Erik Strand's avatar Erik Strand

Start writing C++ node board generator

parent 463bbced
cmake_minimum_required(VERSION 3.13) # 3.13 is required for target_link_options
project(NodeBoard CXX)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
include(cmake/shared_settings.cmake)
find_package(PNG REQUIRED)
add_executable(generate_node_board
main.cpp
png_writer.cpp
png_writer.h
)
target_include_directories(generate_node_board PUBLIC ${PNG_INCLUDE_DIR})
target_link_libraries(generate_node_board shared_settings ${PNG_LIBRARY})
target_compile_features(generate_node_board PUBLIC cxx_std_17)
# This file defines an interface library used to add common compile flags to all libraries and
# executables in FunkyCT.
add_library(shared_settings INTERFACE)
# Warning flags
target_compile_options(shared_settings INTERFACE
-Wall
-Wcast-align
-Wcast-qual
-Wextra
-Wundef
-Wuseless-cast
-Wzero-as-null-pointer-constant
-pedantic
)
# Speed flags
target_compile_options(shared_settings INTERFACE -march=native -ffast-math)
# Build type for profile generation
target_compile_options(shared_settings INTERFACE $<$<CONFIG:ProfileGenerate>:
-fprofile-generate
-O3
-DNDEBUG
>)
target_link_options(shared_settings INTERFACE $<$<CONFIG:ProfileGenerate>:-fprofile-generate>)
# Build type for profile use
target_compile_options(shared_settings INTERFACE $<$<CONFIG:ProfileUse>:
-fprofile-use
-O3
-DNDEBUG
>)
target_link_options(shared_settings INTERFACE $<$<CONFIG:ProfileUse>:-fprofile-use>)
#include "complex_matrix_view.h"
#include "png_writer.h"
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <vector>
namespace funky_ct {
//..................................................................................................
fftw_complex* ComplexMatrixView::row_fftw(uint32_t i) {
return reinterpret_cast<fftw_complex*>(&data_[i * cols_]);
}
//..................................................................................................
fftw_complex const* ComplexMatrixView::row_fftw(uint32_t i) const {
return reinterpret_cast<fftw_complex const*>(&data_[i * cols_]);
}
//..................................................................................................
void ComplexMatrixView::zero_im() {
for (uint32_t i = 0; i < size(); ++i) {
data_[i].imag(0);
}
}
//..................................................................................................
void ComplexMatrixView::swap_quadrants() {
uint32_t const half_rows = rows_ / 2;
uint32_t const half_cols = cols_ / 2;
std::vector<Complex> buffer;
buffer.resize(half_cols);
auto const helper =
[this, &buffer, half_rows, half_cols](uint32_t r0, uint32_t c0, uint32_t r1, uint32_t c1) {
for (uint32_t i = 0; i < half_rows; ++i) {
uint32_t first_src = (r0 + i) * cols_ + c0;
uint32_t first_dst = (r1 + i) * cols_ + c1;
std::copy(&data_[first_src], &data_[first_src + half_cols], buffer.begin());
std::copy(&data_[first_dst], &data_[first_dst + half_cols], &data_[first_src]);
std::copy(buffer.begin(), buffer.end(), &data_[first_dst]);
}
};
helper(0, 0, half_rows, half_cols);
helper(0, half_cols, half_rows, 0);
}
//..................................................................................................
void ComplexMatrixView::swap_half_planes() {
uint32_t const half_rows = rows_ / 2;
uint32_t const half_cols = cols_ / 2;
for (uint32_t i = 0; i < rows_; ++i) {
uint32_t row_start = i * cols_;
for (uint32_t j = 0; j < half_cols; ++j) {
std::swap(data_[row_start + j], data_[row_start + j + half_rows]);
}
}
}
//..................................................................................................
void ComplexMatrixView::print_re_to_cout() {
std::cout << std::fixed << std::setprecision(2);
for (uint32_t i = 0; i < rows_; ++i) {
for (uint32_t j = 0; j < cols_; ++j) {
std::cout << std::setw(6) << (*this)(i, j).real();
}
std::cout << '\n';
}
std::cout << '\n';
}
//..................................................................................................
void ComplexMatrixView::print_im_to_cout() {
std::cout << std::fixed << std::setprecision(2);
for (uint32_t i = 0; i < rows_; ++i) {
for (uint32_t j = 0; j < cols_; ++j) {
std::cout << std::setw(6) << (*this)(i, j).imag();
}
std::cout << '\n';
}
std::cout << '\n';
}
//..................................................................................................
void ComplexMatrixView::print_row_re_to_cout(uint32_t i) {
std::cout << std::scientific << std::setprecision(2);
for (uint32_t j = 0; j < cols_; ++j) {
std::cout << std::setw(10) << (*this)(i, j).real();
}
std::cout << '\n';
}
//..................................................................................................
void ComplexMatrixView::print_row_im_to_cout(uint32_t i) {
std::cout << std::fixed << std::setprecision(2);
for (uint32_t j = 0; j < cols_; ++j) {
std::cout << std::setw(8) << (*this)(i, j).imag();
}
std::cout << '\n';
}
//..................................................................................................
void ComplexMatrixView::print_col_re_to_cout(uint32_t j) {
std::cout << std::scientific << std::setprecision(2);
for (uint32_t i = 0; i < rows_; ++i) {
std::cout << std::setw(10) << (*this)(i, j).real();
}
std::cout << '\n';
}
//..................................................................................................
void ComplexMatrixView::write_png(char const* filename,
double normalization,
uint32_t component) {
auto const get_value = [=](uint32_t x, uint32_t y) -> double {
return reinterpret_cast<double*>(&(*this)(y, x))[component];
};
auto const clamp = [](double x) -> uint8_t {
if (x < 0.5) {
return 0;
}
if (x > 254.5) {
return 255;
}
return static_cast<uint8_t>(x + 0.5);
};
PngWriter png_writer;
png_writer.allocate(cols_, rows_);
if (normalization == 0) {
double min = std::numeric_limits<double>::infinity();
double max = -std::numeric_limits<double>::infinity();
for (uint32_t y = 0; y < rows_; ++y) {
for (uint32_t x = 0; x < cols_; ++x) {
double const value = get_value(x, y);
if (value < min) {
min = value;
}
if (value > max) {
max = value;
}
}
}
double const range = max - min;
for (uint32_t y = 0; y < rows_; ++y) {
for (uint32_t x = 0; x < cols_; ++x) {
png_writer.set_pixel(x, y, clamp((get_value(x, y) - min) / range * 255));
}
}
} else {
for (uint32_t y = 0; y < rows_; ++y) {
for (uint32_t x = 0; x < cols_; ++x) {
png_writer.set_pixel(x, y, clamp(get_value(x, y) / normalization * 255));
}
}
}
png_writer.write(filename);
}
//..................................................................................................
void ComplexMatrixView::write_row_png(
uint32_t row,
char const* filename,
double normalization,
uint32_t component
) {
auto const get_value = [=](uint32_t x, uint32_t y) -> double {
return reinterpret_cast<double*>(&(*this)(y, x))[component];
};
auto const clamp = [](double x) -> uint8_t {
if (x < 0.5) {
return 0;
}
if (x > 254.5) {
return 255;
}
return static_cast<uint8_t>(x + 0.5);
};
PngWriter png_writer;
uint32_t const rows = 10;
png_writer.allocate(cols_, rows);
if (normalization == 0) {
double min = std::numeric_limits<double>::infinity();
double max = -std::numeric_limits<double>::infinity();
for (uint32_t x = 0; x < cols_; ++x) {
double const value = get_value(x, row);
if (value < min) {
min = value;
}
if (value > max) {
max = value;
}
}
double const range = max - min;
for (uint32_t y = 0; y < rows; ++y) {
for (uint32_t x = 0; x < cols_; ++x) {
png_writer.set_pixel(x, y, clamp((get_value(x, row) - min) / range * 255));
}
}
} else {
for (uint32_t y = 0; y < rows; ++y) {
for (uint32_t x = 0; x < cols_; ++x) {
png_writer.set_pixel(x, y, clamp(get_value(x, row) / normalization * 255));
}
}
}
png_writer.write(filename);
}
}
#include "png_writer.h"
#include <iostream>
//--------------------------------------------------------------------------------------------------
int main() {
// All length measurements are in mm.
double width = 6;
double height = 14;
double ppmm = 50;
auto const to_px = [ppmm](double x) {
return static_cast<uint32_t>(ppmm * x);
};
uint32_t width_px = to_px(width);
uint32_t height_px = to_px(height);
PngWriter png_writer;
png_writer.allocate(width_px, height_px);
png_writer.set_all_pixels_black();
for (uint32_t y = 0; y < 10; ++y) {
for (uint32_t x = 0; x < 10; ++x) {
png_writer.set_pixel(x, y, 255);
}
}
png_writer.write("node_board_traces.png");
return 0;
}
#include "png_writer.h"
#include <stdlib.h>
#include <stdio.h>
#include <cstring>
#include <iostream>
//..................................................................................................
PngWriter::PngWriter(): width_(0), height_(0), row_pointers_(nullptr) {}
//..................................................................................................
PngWriter::~PngWriter() {
if (row_pointers_ != nullptr) {
free();
}
}
//..................................................................................................
void PngWriter::free() {
for (int32_t y = 0; y < height_; y++) {
std::free(row_pointers_[y]);
}
std::free(row_pointers_);
width_ = 0;
height_ = 0;
}
//..................................................................................................
void PngWriter::allocate(int32_t width, int32_t height) {
if (row_pointers_ != nullptr) {
free();
}
width_ = width;
height_ = height;
row_pointers_ = (png_bytep*)malloc(sizeof(png_bytep) * height_);
for (int y = 0; y < height_; y++) {
row_pointers_[y] = (png_bytep)malloc(row_size());
}
}
//..................................................................................................
void PngWriter::set_pixel(int32_t x, int32_t y, uint8_t value) {
png_bytep row = row_pointers_[y];
png_bytep px = &(row[x * 3]);
px[0] = value;
px[1] = value;
px[2] = value;
}
//..................................................................................................
void PngWriter::set_all_pixels_black() {
for (int y = 0; y < height_; y++) {
std::memset(row_pointers_[y], 0, row_size());
}
//for(int x = 0; x < width; x++) {
// png_bytep px = &(row[x * 3]);
// px[0] = 0;
// px[1] = 0;
// px[2] = 0;
//}
}
//..................................................................................................
void PngWriter::write(char const* filename) {
auto fp = fopen(filename, "wb");
if (!fp) {
std::cout << "Couldn't make file\n";
abort();
}
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png) {
std::cout << "Couldn't make png_structp\n";
abort();
}
png_infop info = png_create_info_struct(png);
if (!info) {
std::cout << "Couldn't make png_structp\n";
abort();
}
if (setjmp(png_jmpbuf(png))) {
std::cout << "Couldn't set jump\n";
abort();
}
png_init_io(png, fp);
// Output is 8bit depth, RGB format.
png_set_IHDR(png,
info,
width_,
height_,
8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
png_write_info(png, info);
if (png_get_rowbytes(png, info) != row_size()) {
std::cout << "Allocated bad amount of memory\n";
abort();
}
// To remove the alpha channel for PNG_COLOR_TYPE_RGB format,
// Use png_set_filler().
//png_set_filler(png_, 0, PNG_FILLER_AFTER);
png_write_image(png, row_pointers_);
png_write_end(png, NULL);
if (png && info) {
png_destroy_write_struct(&png, &info);
}
fclose(fp);
}
#include <png.h>
#include <cstdint>
//--------------------------------------------------------------------------------------------------
// This class is derived from code by Guillaume Cottenceau, copyright 2002-2010 and distributed
// under the X11 license. https://gist.github.com/niw/5963798
class PngWriter {
public:
PngWriter();
~PngWriter();
void free();
void allocate(int32_t width, int32_t height);
png_bytep* row_pointers() { return row_pointers_; }
void set_pixel(int32_t x, int32_t y, uint8_t value = 255);
void set_all_pixels_black();
void write(char const* filename);
private:
uint32_t row_size() { return 3 * width_; }
int32_t width_;
int32_t height_;
png_bytep* row_pointers_;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment