#include "LEDVideoWall.h" #include "cli.hpp" #include LEDVideoWall::~LEDVideoWall() { } LEDVideoWall* LEDVideoWall::Freeform(mm panel_width, mm panel_height, mm wall_max_width, mm wall_max_height) { unsigned int columns = wall_max_width / panel_width; unsigned int rows = wall_max_height / panel_height; return new LEDVideoWall( columns * panel_width, rows * panel_height, columns, rows); } #define CMP_EPSILON 0.0000001 // GCD is available in stl from C++17 onwards, but I'm still reimplementing it unsigned int gcd(unsigned int a, unsigned int b) { // Eucledian algorithm https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclidean_algorithm if (b == 0) return a; return gcd(b, a % b); } LEDVideoWall* LEDVideoWall::Aspect(mm panel_width, mm panel_height, unsigned int aspect_width, unsigned int aspect_height) { // Simplify the fraction (aspect), because we want the smallest screen size // For example, turn 16:10 into 8:5 unsigned int aspect_gcd = gcd(aspect_width, aspect_height); aspect_width /= aspect_gcd; aspect_height /= aspect_gcd; return new LEDVideoWall( aspect_width * panel_width, aspect_height * panel_height, aspect_width, aspect_height); } LEDVideoWall::LEDVideoWall( mm width, mm height, unsigned int columns_of_panels, unsigned int rows_of_panels) : Screen(width, height), columns_of_panels(columns_of_panels), rows_of_panels(rows_of_panels) { } enum class LEDVideoWallType { Freeform = 0, Aspect }; LEDVideoWall* LEDVideoWall::fromCommandLine() { mm ipanel_width = 0, ipanel_height = 0; do { cli::scanTwoValues( "%dx%d", ipanel_width, ipanel_height, "Enter panel size (in the format 'WIDTHxHEIGHT'): ", "Invalid size, try again!"); if (ipanel_width == 0 || ipanel_height == 0) { std::cerr << "The panel width or height cannot be zero!" << std::endl; continue; } break; } while (true); unsigned int itype = 2; cli::readUserInputMax( itype, (unsigned int)2, "Select an LED video wall type [0 for Freeform, 1 for Aspect]: ", "Invalid type, try again!"); LEDVideoWallType type = static_cast(itype); switch (type) { case LEDVideoWallType::Freeform: { mm iwall_max_width = 0, iwall_max_height = 0; do { cli::scanTwoValues( "%dx%d", iwall_max_width, iwall_max_height, "Enter singe wall size (in the format 'WIDTHxHEIGHT'): ", "Invalid size, try again!"); if (iwall_max_width == 0 || iwall_max_height == 0) { std::cerr << "The wall width or height cannot be zero!" << std::endl; continue; } if (iwall_max_width < ipanel_width || iwall_max_height < ipanel_height) { std::cerr << "The wall cannot be smaller than the panel!" << std::endl; continue; } break; } while (true); return LEDVideoWall::Freeform(ipanel_width, ipanel_height, iwall_max_width, iwall_max_height); }; case LEDVideoWallType::Aspect: { mm iaspect_width = 0, iaspect_height = 0; do { cli::scanTwoValues( "%d:%d", iaspect_width, iaspect_height, "Enter aspect ratio (in the format 'WIDTH:HEIGHT'): ", "Invalid input, try again!"); if (iaspect_width == 0 || iaspect_height == 0) { std::cerr << "The aspect ratio width or height cannot be zero!" << std::endl; continue; } break; } while (true); return LEDVideoWall::Aspect(ipanel_width, ipanel_height, iaspect_width, iaspect_height); }; } throw std::logic_error("Implementation error: didn't handle all types of LED video walls!"); } std::string LEDVideoWall::extraOutput() const { std::ostringstream output; output << " (" << this->columns_of_panels << " columns by " << this->rows_of_panels << " rows of tiles)"; return output.str(); }