//############################################################################
//
// LaserBoy !!!
//
// by James Lehman
// Extra Stimulus Inc.
// james@akrobiz.com
//
// began: October 2003
//
// Copyright 2003 to 2025 James Lehman.
// This source is distributed under the terms of the GNU General Public License.
//
// LaserBoy_segment.hpp is part of LaserBoy.
//
// LaserBoy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// LaserBoy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with LaserBoy. If not, see .
//
//############################################################################
#ifndef __LASERBOY_SEGMENT_DEFINITIONS__
#define __LASERBOY_SEGMENT_DEFINITIONS__
//############################################################################
#include "LaserBoy_bmp.hpp"
#include "LaserBoy_real_segment_set.hpp"
//############################################################################
class LaserBoy_segment : public vector
{
public:
LaserBoy_segment()
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{}
//------------------------------------------------------------------------
LaserBoy_segment(const int& palette_index,
bool add_origin
)
: vector(),
palette_index (palette_index),
segment_error (LASERBOY_OK)
{
if(add_origin)
{
reserve(2);
push_back(LaserBoy_vertex());
push_back(LaserBoy_vertex());
}
}
//------------------------------------------------------------------------
LaserBoy_segment(const LaserBoy_segment& segment)
: vector(),
palette_index (segment.palette_index),
segment_error (LASERBOY_OK)
{
reserve(segment.size());
insert(end(), segment.begin(), segment.end());
}
//------------------------------------------------------------------------
LaserBoy_segment(const LaserBoy_real_segment& rs)
: vector(),
palette_index (rs.palette_index),
segment_error (LASERBOY_OK)
{
reserve(rs.size());
for(size_t i = 0; i < rs.size(); i++)
push_back((LaserBoy_vertex)rs[i]);
}
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short from,
LaserBoy_vertex to
); // the line
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short from,
LaserBoy_vertex to,
const u_int& max_d
); // the line
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_vertex p1,
LaserBoy_vertex p2,
string font,
string text
); // mono spaced font constructor
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_vertex p1,
LaserBoy_vertex p2,
string font,
string text,
int dud
); // variable spaced font constructor
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short arc_start,
double arc_angle // OK degrees, whatever!
); // circular arc constructor
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short arc_start,
double arc_angle,
double radii_ratio
); // elliptical arc constructor
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short first_vertex,
u_int number_of_sides
); // polygon constructor
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short first_vertex,
u_int number_of_sides,
double ratio
); // polystar constructor
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short center,
u_int radius,
u_int rhodonea_numerator,
u_int rhodonea_denominator
); // rhodonea
//------------------------------------------------------------------------
LaserBoy_segment(u_int fixed_radius,
LaserBoy_3D_short center,
u_int roller_radius,
int roller_offset
); // epitrochoid (and epicycloid)
//------------------------------------------------------------------------
LaserBoy_segment(u_int fixed_radius,
u_int roller_radius,
int roller_offset,
LaserBoy_3D_short center
); // hypotrochoid (and hypocycloid)
//------------------------------------------------------------------------
LaserBoy_segment(LaserBoy_3D_short center,
u_int amplitude_x,
u_int amplitude_y,
u_int frequency_x,
u_int frequency_y,
double phase_x,
double phase_y
); // Lissajous curve
//------------------------------------------------------------------------
~LaserBoy_segment()
{}
//------------------------------------------------------------------------
bool operator == (const LaserBoy_segment& segment)
{
if(palette_index != segment.palette_index)
return false;
if(size() != segment.size())
return false;
for(size_t i = 0; i < size(); i++)
if(at(i) != segment.at(i))
return false;
return true;
}
//------------------------------------------------------------------------
LaserBoy_segment& operator += (LaserBoy_segment segment)
{
if(palette_index != segment.palette_index)
{
promote_to_true_color();
segment.promote_to_true_color();
}
insert(end(), segment.begin(), segment.end());
return *this;
}
//------------------------------------------------------------------------
LaserBoy_segment& operator += (const LaserBoy_vertex& vertex)
{
push_back(vertex);
return *this;
}
//------------------------------------------------------------------------
LaserBoy_segment operator + (LaserBoy_segment segment) const
{
LaserBoy_segment sum(*this);
if(sum.palette_index != segment.palette_index)
{
sum.promote_to_true_color();
segment.promote_to_true_color();
}
sum.insert(end(), segment.begin(), segment.end());
sum.sync_rgb_and_palette();
return sum;
}
//------------------------------------------------------------------------
LaserBoy_segment operator + (const LaserBoy_vertex& vertex) const
{
LaserBoy_segment sum(*this);
sum.push_back(vertex);
return sum;
}
//------------------------------------------------------------------------
LaserBoy_segment& operator = (const LaserBoy_segment& segment)
{
palette_index = segment.palette_index;
segment_error = segment.segment_error;
clear();
reserve(segment.size());
insert(begin(), segment.begin(), segment.end());
shrink_to_fit();
return *this;
}
//------------------------------------------------------------------------
LaserBoy_segment& operator = (const LaserBoy_real_segment& real_segment)
{
palette_index = real_segment.palette_index;
segment_error = real_segment.real_segment_error;
clear();
reserve(real_segment.size());
for(size_t i = 0; i < real_segment.size(); i++)
push_back((LaserBoy_vertex)real_segment[i]);
shrink_to_fit();
return *this;
}
//------------------------------------------------------------------------
bool is_2D() const
{
if(size() > 1)
{
for(size_t i = 0; i < size(); i++)
if(at(i).z != 0)
return false;
}
return true;
}
//------------------------------------------------------------------------
bool is_flat_in_x() const
{
if(size() > 1)
{
short _x = first_lit_anchor().x;
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit() && at(i).x != _x)
return false;
}
return true;
}
//------------------------------------------------------------------------
bool is_flat_in_y() const
{
if(size() > 1)
{
short _y = first_lit_anchor().y;
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit() && at(i).y != _y)
return false;
}
return true;
}
//------------------------------------------------------------------------
bool is_flat_in_z() const
{
if(size() > 1)
{
short _z = first_lit_anchor().z;
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit() && at(i).z != _z)
return false;
}
return true;
}
//------------------------------------------------------------------------
bool at_index_has_magnitude(size_t vertex_index) const
{
if( vertex_index // != 0
&& vertex_index < size()
)
{
return (bool)(at(vertex_index - 1) | at(vertex_index)); // distance
}
else
return false;
}
//------------------------------------------------------------------------
double front_to_back_magnitude() const
{
return (front() | back());
}
//------------------------------------------------------------------------
LaserBoy_vertex first_lit_vertex() const
{
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit())
return at(i);
return LaserBoy_vertex(0);
}
//------------------------------------------------------------------------
int first_lit_vector_index() const
{
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit())
return i;
return -1;
}
//------------------------------------------------------------------------
LaserBoy_vertex first_lit_anchor() const
{
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit())
return at(i - 1);
return LaserBoy_vertex(0);
}
//------------------------------------------------------------------------
int first_lit_anchor_index() const
{
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit())
return (i - 1);
return -1;
}
//------------------------------------------------------------------------
int last_lit_anchor_index() const
{
for(size_t i = size() - 1; i > 0; i--)
if(at(i).is_lit())
return i - 1;
return -1;
}
//------------------------------------------------------------------------
LaserBoy_vertex last_lit_anchor() const
{
for(size_t i = size() - 1; i > 0; i--)
if(at(i).is_lit())
return at(i - 1);
return LaserBoy_vertex(0);
}
//------------------------------------------------------------------------
LaserBoy_vertex last_lit_vector() const
{
for(size_t i = size() - 1; i > 0; i--)
if(at(i).is_lit())
return at(i);
return LaserBoy_vertex(0);
}
//------------------------------------------------------------------------
int last_lit_vector_index() const
{
for(size_t i = size() - 1; i > 0; i--)
if(at(i).is_lit())
return i;
return -1;
}
//------------------------------------------------------------------------
int number_of_lit_vectors() const
{
int count = 0;
for(size_t i = 1; i < size(); i++)
if(at(i).is_lit())
count++;
return count;
}
//------------------------------------------------------------------------
size_t number_of_color_vectors() const;
size_t number_of_dark_vectors () const;
//------------------------------------------------------------------------
int number_of_blank_vectors() const
{
int count = 1; //first vertex is always an anchor
for(size_t i = 1; i < size(); i++)
if(at(i).is_blank())
count++;
return count;
}
//------------------------------------------------------------------------
int number_of_unique_colors() const
{
if(size() > 1)
{
size_t i,
j;
LaserBoy_palette palette;
if(first_lit_vector_index() > -1)
{
palette.push_back((LaserBoy_color)first_lit_vertex());
for(i = first_lit_vector_index() + 1; i < size(); i++)
{
for(j = 0; j < palette.number_of_colors(); j++)
{
if(palette[j] == (LaserBoy_color)at(i))
break;
}
if( j == palette.number_of_colors() // color not found
&& at(i).is_lit()
)
palette.push_back((LaserBoy_color)at(i));
}
return palette.number_of_colors();
}
}
return 0;
}
//------------------------------------------------------------------------
LaserBoy_segment& remove_vertex(size_t vertex_index)
{
if(size() <= 2) // takes 2 vertices to make a vector!
clear();
else if(vertex_index < size())
{
size_t i;
LaserBoy_segment s(palette_index, false);
s.reserve(size() - 1);
for(i = 0; i < vertex_index; i++)
s += at(i);
for(i = vertex_index + 1; i < size(); i++)
s += at(i);
*this = s;
}
return *this;
}
//------------------------------------------------------------------------
LaserBoy_3D_short segment_front () const ;
LaserBoy_3D_short segment_back () const ;
LaserBoy_3D_short segment_top () const ;
LaserBoy_3D_short segment_bottom () const ;
LaserBoy_3D_short segment_right () const ;
LaserBoy_3D_short segment_left () const ;
short max_x () const ;
short max_y () const ;
short max_z () const ;
short min_x () const ;
short min_y () const ;
short min_z () const ;
LaserBoy_3D_short max_off_axis_xyz () const ;
double max_distance_from_origin () const ;
double max_distance_from_origin_xy () const ;
double max_distance_from_origin_zy () const ;
double min_distance_from_origin () const ;
double min_distance_from_origin_xy () const ;
u_short height () const ;
u_short width () const ;
u_short depth () const ;
u_short max_dimension () const ;
double relative_volume () const ;
double relative_volume_to_origin () const ;
bool is_closed_polygon () const ;
bool segment_passes_through_origin () const ;
LaserBoy_segment& reverse ();
LaserBoy_segment& reverse_sub_segment (size_t p1, size_t p2);
LaserBoy_segment& reorder_from (size_t vertex_index);
LaserBoy_segment& randomize_segments ();
LaserBoy_segment& conglomerate_lit_segments ();
LaserBoy_segment shortest_path_of_segments (const LaserBoy_segment& previous_frame);
void blank_all_vertices ();
void unblank_all_vertices ();
void blacken_vertices ();
void reduce_blank_vectors ();
void omit_equivalent_vectors ();
void remove_dots ();
LaserBoy_Error_Code enhance_dots ();
void remove_dwell_vertices ();
void remove_short_vectors ();
void reduce_lit_vectors ();
void impose_bit_resolution ();
LaserBoy_Error_Code reorder_segments (const LaserBoy_segment& previous_frame);
LaserBoy_Error_Code fracture_segments ();
LaserBoy_Error_Code bond_segments ();
LaserBoy_Error_Code add_vertex (size_t vertex_index);
LaserBoy_Error_Code break_segment (size_t& vertex_index);
LaserBoy_Error_Code connect_the_dots (size_t p1, size_t p2); // vertex indices
double vector_angle (size_t vertex) const ;
double total_angle () const ;
double max_angle () const ;
double total_magnitude () const ;
double max_magnitude () const ;
double max_color_magnitude () const ;
double max_dark_magnitude () const ;
double length_in_seconds () const ;
LaserBoy_Error_Code add_dwell ();
LaserBoy_Error_Code add_lit_span_vertices ();
void add_lit_span_vertices (const u_int& max_d);
LaserBoy_Error_Code add_blank_span_vertices ();
LaserBoy_Error_Code add_blank_span_vertices (u_int max_d);
LaserBoy_segment& flip (u_int plane);
LaserBoy_segment& quarter_turn (u_int plane, u_int turns);
LaserBoy_segment& normalize (double scale);
LaserBoy_segment& normalize_vectors (double scale);
LaserBoy_segment& normalize_vectors_with_origin (double scale);
LaserBoy_segment& z_order_vertices (unsigned short span);
LaserBoy_segment& flatten_z ();
LaserBoy_segment& flat_to_2D ();
LaserBoy_segment& center_x ();
LaserBoy_segment& center_y ();
LaserBoy_segment& center_z ();
LaserBoy_segment& center ();
//------------------------------------------------------------------------
LaserBoy_Bounds rotate (LaserBoy_3D_double a);
LaserBoy_Bounds rotate_around_origin (LaserBoy_3D_double a);
//------------------------------------------------------------------------
LaserBoy_Bounds rotate_on_coordinates (LaserBoy_3D_double p,
LaserBoy_3D_double a
);
//------------------------------------------------------------------------
LaserBoy_Bounds rotate_on_coordinates_x (LaserBoy_3D_double p, double a);
LaserBoy_Bounds rotate_on_coordinates_y (LaserBoy_3D_double p, double a);
LaserBoy_Bounds rotate_on_coordinates_z (LaserBoy_3D_double p, double a);
LaserBoy_Bounds rotate_around_origin ();
//------------------------------------------------------------------------
void ripple (int direction,
double amplitude,
double freq ,
double phase
);
//------------------------------------------------------------------------
LaserBoy_palette as_color_table () const ;
void strip_color ();
void strip_color_rgb (const LaserBoy_color& c);
void strip_color_or ();
void strip_color_avg ();
void to_palette_by_index (int index);
void to_target_palette_by_index ();
void best_match_palette (int index);
void best_match_target_palette ();
void convert_black_to_blank ();
void convert_black_to_color ();
void convert_blank_to_black ();
void set_vertex_to_black (int index);
void impose_black_level ();
//------------------------------------------------------------------------
void index_palette (int index_multiple, int offset);
void index_segments_palette (int index_multiple, int offset);
void span_palette (double span_factor, int offset);
void span_x_palette (double span_factor, int offset);
void span_y_palette (double span_factor, int offset);
void span_z_palette (double span_factor, int offset);
void span_radial_palette (double span_factor, int offset);
void span_axial_palette (double span_factor, int offset);
void span_segments_palette (double span_factor, int offset);
void random_color_vectors_palette (int index_multiple);
void random_color_segments_palette ();
//------------------------------------------------------------------------
void index_hues (int index_multiple, int offset);
void index_segments_hues (int index_multiple, int offset);
void span_hues (double span_factor, int offset);
void span_x_hues (double span_factor, int offset);
void span_y_hues (double span_factor, int offset);
void span_z_hues (double span_factor, int offset);
void span_radial_hues (double span_factor, int offset);
void span_axial_hues (double span_factor, int offset);
void span_segments_hues (double span_factor, int offset);
void random_color_vectors_hues (int index_multiple);
void random_color_segments_hues ();
//------------------------------------------------------------------------
LaserBoy_segment& rotate_colors (int steps );
bool find_rgb_in_palette (const LaserBoy_palette& palette);
void set_rgb_from_palette ();
void set_palette_to_332 ();
void sync_rgb_and_palette ();
void bit_reduce_to_palette ();
void best_reduce_to_palette ();
void promote_to_true_color ();
void shade (u_char shade);
void tint (u_char tint);
LaserBoy_Error_Code color_from_bmp (const string& file);
void color_from_bmp (struct LaserBoy_bmp* bmp);
LaserBoy_Error_Code subtract_bmp (const string& file);
void subtract_bmp (struct LaserBoy_bmp* bmp);
//------------------------------------------------------------------------
LaserBoy_Bounds apply_view ();
//------------------------------------------------------------------------
LaserBoy_Bounds move (LaserBoy_3D_double d);
LaserBoy_Bounds move ();
//------------------------------------------------------------------------
LaserBoy_Bounds scale (LaserBoy_3D_double s);
LaserBoy_Bounds scale_on_coordinates (LaserBoy_3D_double p,
LaserBoy_3D_double s
);
//------------------------------------------------------------------------
LaserBoy_Bounds scale_around_origin (LaserBoy_3D_double s);
LaserBoy_Bounds scale_around_origin ();
LaserBoy_3D_double rectangular_center_of () const ;
LaserBoy_3D_double mean_of_coordinates () const ;
LaserBoy_3D_double centroid_of_coordinates_xy (double& area, LaserBoy_segment& s) const ;
LaserBoy_3D_double centroid_of_coordinates_zy (double& area, LaserBoy_segment& s) const ;
LaserBoy_3D_double centroid_of_coordinates_xz (double& area, LaserBoy_segment& s) const ;
LaserBoy_3D_double centroid_of_coordinates () const ;
size_t number_of_segments () const ;
//------------------------------------------------------------------------
LaserBoy_segment blend (const LaserBoy_segment& segment,
double ratio
);
//------------------------------------------------------------------------
bool find_segment_at_index (size_t index,
size_t& start,
size_t& end
) const ;
//------------------------------------------------------------------------
bool find_segment_of_vertex (size_t vertex_index,
size_t& start,
size_t& end,
size_t& segment_index
) const ;
//------------------------------------------------------------------------
bool same_as (const LaserBoy_segment& segment) const ;
//------------------------------------------------------------------------
LaserBoy_segment copy_segment (size_t index) const ;
LaserBoy_frame_set explode_segments () const ;
LaserBoy_3D_double rectangular_center_of_segment (size_t index) const ;
LaserBoy_3D_double mean_of_coordinates_of_segment(size_t index) const ;
LaserBoy_3D_double centroid_of_segment_xy (size_t index, double& area, LaserBoy_segment& s) const ;
LaserBoy_3D_double centroid_of_segment_zy (size_t index, double& area, LaserBoy_segment& s) const ;
LaserBoy_3D_double centroid_of_segment_xz (size_t index, double& area, LaserBoy_segment& s) const ;
LaserBoy_3D_double centroid_of_segment (size_t index) const ;
size_t segment_index_of_vertex (size_t index) const ;
LaserBoy_Bounds move_segment (size_t index, LaserBoy_3D_double d);
LaserBoy_Bounds rotate_segment (size_t index, LaserBoy_3D_double a);
LaserBoy_Bounds rotate_segment_around_origin (size_t index, LaserBoy_3D_double a);
LaserBoy_Bounds scale_segment (size_t index, LaserBoy_3D_double m);
LaserBoy_Bounds scale_segment_around_origin (size_t index, LaserBoy_3D_double m);
//------------------------------------------------------------------------
LaserBoy_real_segment to_real_segment (bool add_origin = false) const ;
//------------------------------------------------------------------------
void to_fstream_wav (std::fstream& out,
LaserBoy_wav_header& header,
bool end_of_frame = false,
bool unique_frame = false
);
//------------------------------------------------------------------------
int palette_index;
LaserBoy_Error_Code segment_error;
};
//############################################################################
#endif
//############################################################################
//////////////////////////////////////////////////////////////////////////////
//############################################################################