Forked from
aevol / aevol
3384 commits behind, 51 commits ahead of the upstream repository.
-
David Parsons authoredDavid Parsons authored
Individual_X11.cpp 29.90 KiB
// ****************************************************************************
//
// Aevol - An in silico experimental evolution platform
//
// ****************************************************************************
//
// Copyright: See the AUTHORS file provided with the package or <www.aevol.fr>
// Web: http://www.aevol.fr/
// E-mail: See <http://www.aevol.fr/contact/>
// Original Authors : Guillaume Beslon, Carole Knibbe, David Parsons
//
// This program 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 2 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
// ****************************************************************************
// =================================================================
// Libraries
// =================================================================
#include <stdio.h>
#include <math.h>
// =================================================================
// Project Files
// =================================================================
#include "Individual_X11.h"
#include "ExpManager.h"
#include "ExpSetup.h"
#include "Utils.h"
namespace aevol {
//##############################################################################
// #
// Class Individual_X11 #
// #
//##############################################################################
// =================================================================
// Definition of static attributes
// =================================================================
// =================================================================
// Constructors
// =================================================================
Individual_X11::Individual_X11(ExpManager * exp_manager, gzFile backup_file) :
Individual(exp_manager, backup_file)
{
init_occupied_sectors();
}
Individual_X11::Individual_X11(const Individual_X11 &model) :
Individual(model)
{
init_occupied_sectors();
}
Individual_X11::Individual_X11(Individual_X11 * const parent,
int32_t id,
std::shared_ptr<JumpingMT> mut_prng,
std::shared_ptr<JumpingMT> stoch_prng) :
Individual(parent, id, mut_prng, stoch_prng)
{
init_occupied_sectors();
}
Individual_X11::Individual_X11(ExpManager * exp_m, std::shared_ptr<JumpingMT> mut_prng,
std::shared_ptr<JumpingMT> stoch_prng, std::shared_ptr<MutationParams> param_mut,
double w_max, int32_t min_genome_length, int32_t max_genome_length, bool allow_plasmids,
int32_t id, const char* strain_name, int32_t age) :
Individual(exp_m,mut_prng,stoch_prng,param_mut,w_max,min_genome_length,
max_genome_length,allow_plasmids,id,strain_name,age) {
init_occupied_sectors();
}
/*Individual_X11::Individual_X11(char* genome, int32_t genome_size) : Individual(genome, genome_size)
{
init_occupied_sectors();
}*/
// =================================================================
// Destructors
// =================================================================
Individual_X11::~Individual_X11()
{
for (int16_t layer = 0 ; layer < outmost_layer_ ; layer++)
{
delete [] occupied_sectors_[LEADING][layer];
delete [] occupied_sectors_[LAGGING][layer];
}
}
// =================================================================
// Public Methods
// =================================================================
void Individual_X11::display()
{
}
void Individual_X11::display_cdss(X11Window * win)
{
// Retreive the genetic unit corresponding to the main chromosome
GeneticUnit* gen_unit = &genetic_unit_list_.front();
int32_t genome_length = gen_unit->dna()->length();
// Display the number of CDSs
char display_string[40];
sprintf(display_string, "Main chromosome size : %" PRId32 "bp", genome_length);
win->draw_string(15, 25, display_string);
sprintf(display_string, "Leading : %" PRId32 " CDSs", static_cast<int32_t>(gen_unit->protein_list(LEADING).size()));
win->draw_string(15, 40, display_string);
sprintf(display_string, "Lagging : %" PRId32 " CDSs", static_cast<int32_t>(gen_unit->protein_list(LAGGING).size()));
win->draw_string(15, 55, display_string);
// Compute display diameter according to genome length and window size
int16_t canvas_width;
if (allow_plasmids_) canvas_width = win->width() / 2;
else canvas_width = win->width();
int16_t canvas_height = win->height();
int16_t canvas_size = Utils::min(canvas_width, canvas_height);
int16_t diam = round(canvas_size * log((double)genome_length) / 16);
// Prevent diameter from getting greater than 2/3 of the window size
if (diam > 2 * canvas_size / 3)
{
diam = 2 * canvas_size / 3;
}
// Compute coordinates of the upper-left corner of the containing square
int16_t pos_x = (canvas_width - diam) / 2;
int16_t pos_y = (canvas_height - diam) / 2;
// Draw main circle
win->draw_circle(pos_x, pos_y, diam);
// Sector occupation management
reset_sectors();
// ---------------
// Draw each CDS
// ---------------
// NB : As we want OriC to be at the "top" of the circle and the orientation
// to be clockwise, the drawing angle (theta) will be given as
// (90 - alpha), alpha being the "classical" trigonometric angle
int16_t alpha_first, alpha_last; // Angles of first and last transcribed bases from OriC (degrees)
int16_t theta_first; //, theta_last; // Transposed angles on the trigonometric circle (degrees)
int16_t nb_sect;
// Same as above with precision = 1/64 degree
int16_t alpha_first_64, alpha_last_64;
int16_t theta_first_64; //, theta_last_64;
int16_t nb_sect_64;
// ----------------
// LEADING strand
// ----------------
for (const auto& cds: gen_unit->protein_list(LEADING))
{
// Alpha : angles from OriC (in degrees)
// Theta : angles on the trigonometric circle (in degrees)
// nb_sect : "length" in degrees of the arc to be drawn
alpha_first = (int16_t) round(360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last = (int16_t) round(360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first = Utils::mod(90 - alpha_first, 360);
// theta_last = Utils::mod(90 - alpha_last, 360);
nb_sect = Utils::mod(alpha_last - alpha_first + 1, 360);
// These are the same as above but with a higher precision (1/64 degrees)
alpha_first_64 = (int16_t) round(64 * 360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last_64 = (int16_t) round(64 * 360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first_64 = Utils::mod(64 * 90 - alpha_first_64, 64 * 360);
// theta_last_64 = Utils::mod(64 * 90 - alpha_last_64, 64 * 360);
nb_sect_64 = Utils::mod(alpha_last_64 - alpha_first_64 + 1, 64 * 360);
// Look for the inmost layer that has all the sectors between
// theta_first and theta_last free
int16_t layer = 0;
bool sectors_free = false;
while (! sectors_free)
{
sectors_free = true;
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
if (occupied_sectors_[LEADING][layer][Utils::mod(theta_first-rho, 360)])
{
sectors_free = false;
break;
}
}
if (sectors_free)
{
break; // All the needed sectors are free on the current layer
}
else
{
layer++;
if (layer >= outmost_layer_)
{
add_layer();
break; // An added layer is necessarily free, no need to look further
}
}
}
// Mark sectors to be drawn as occupied
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
occupied_sectors_[LEADING][layer][Utils::mod(theta_first-rho, 360)] = true;
}
// Mark flanking sectors as occupied
occupied_sectors_[LEADING][layer][Utils::mod(theta_first+1, 360)] = true;
occupied_sectors_[LEADING][layer][Utils::mod(theta_first-nb_sect, 360)] = true;
// Draw
const int8_t cds_layer_spacing = 5; // TODO : param?
layer++; // index starting at 0 but needed to start at 1
int16_t diam2 = diam + (layer * 2 * cds_layer_spacing);
pos_x = (int16_t) round((double)(canvas_width - diam2) / 2.0);
pos_y = (int16_t) round((double)(canvas_height - diam2) / 2.0);
char* color = X11Window::color(cds.mean());
win->draw_arc_64(pos_x, pos_y, diam2, theta_first_64 - nb_sect_64, nb_sect_64, color);
delete [] color;
}
// ----------------
// LAGGING strand
// ----------------
for (const auto& cds: gen_unit->protein_list(LAGGING))
{
// Alpha : angles from OriC (in degrees)
// Theta : angles on the trigonometric circle (in degrees)
// nb_sect : "length" in degrees of the arc to be drawn
alpha_first = (int16_t) round(360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last = (int16_t) round(360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first = Utils::mod(90 - alpha_first, 360);
// theta_last = Utils::mod(90 - alpha_last, 360);
nb_sect = Utils::mod(alpha_first - alpha_last + 1, 360);
// These are the same as above but with a higher precision (1/64 degrees)
alpha_first_64 = (int16_t) round(64 * 360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last_64 = (int16_t) round(64 * 360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first_64 = Utils::mod(64 * 90 - alpha_first_64, 64 * 360);
// theta_last_64 = Utils::mod(64 * 90 - alpha_last_64, 64 * 360);
nb_sect_64 = Utils::mod(alpha_first_64 - alpha_last_64 + 1, 64 * 360);
// Look for the inmost layer that has all the sectors between
// theta_first and theta_last free
int16_t layer = 0;
bool sectors_free = false;
while (! sectors_free)
{
sectors_free = true;
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
if (occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+rho, 360)])
{
sectors_free = false;
break;
}
}
if (sectors_free)
{
break; // All the needed sectors are free on the current layer
}
else
{
layer++;
if (layer >= outmost_layer_)
{
add_layer();
break; // An added layer is necessarily free, no need to look further
}
}
}
// Mark sectors to be drawn as occupied
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+rho, 360)] = true;
}
// Mark flanking sectors as occupied
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first-1, 360)] = true;
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+nb_sect, 360)] = true;
// Draw
const int8_t cds_layer_spacing = 5; // TODO : param?
layer++; // index starting at 0 but needed to start at 1
int16_t diam2 = diam - (layer * 2 * cds_layer_spacing);
pos_x = (int16_t) round((double)(canvas_width - diam2) / 2.0);
pos_y = (int16_t) round((double)(canvas_height - diam2) / 2.0);
char* color = X11Window::color(cds.mean());
win->draw_arc_64(pos_x, pos_y, diam2, theta_first_64, nb_sect_64, color);
delete [] color;
}
// --------------------------------------------------------------------------This is temporary, it is a big copy-paste of what's above.
if (allow_plasmids_)
{
// Retreive the genetic unit corresponding to the plasmid (i.e. index 1 in genetic_unit_list_)
GeneticUnit* gen_unit = &*std::next(genetic_unit_list_.begin());
if (gen_unit == NULL) return;
int32_t genome_length = gen_unit->dna()->length();
// Compute display diameter according to genome length and window size
int16_t canvas_width;
int16_t canvas_height;
int16_t canvas_size ;
if (allow_plasmids_)
{
canvas_width = win->width() / 2;
canvas_size = canvas_width;
}
else
{
canvas_width = win->width();
canvas_size = Utils::min(canvas_width, canvas_width);
}
canvas_height = win->height();
int16_t diam = round(canvas_size * log((double)genome_length) / 16);
// Prevent diameter from getting greater than 2/3 of the window size
if (diam > 2 * canvas_size / 3)
{
diam = 2 * canvas_size / 3;
}
// Compute coordinates of the upper-left corner of the containing square
int16_t pos_x = canvas_width + (canvas_width - diam) / 2;
int16_t pos_y = (canvas_height - diam) / 2;
// Draw main circle
win->draw_circle(pos_x, pos_y, diam);
// Sector occupation management
reset_sectors();
// ---------------
// Draw each CDS
// ---------------
// NB : As we want OriC to be at the "top" of the circle and the orientation
// to be clockwise, the drawing angle (theta) will be given as
// (90 - alpha), alpha being the "classical" trigonometric angle
int16_t alpha_first, alpha_last; // Angles of first and last transcribed bases from OriC (degrees)
int16_t theta_first; //, theta_last; // Transposed angles on the trigonometric circle (degrees)
int16_t nb_sect;
// Same as above with precision = 1/64 degree
int16_t alpha_first_64, alpha_last_64;
int16_t theta_first_64; //, theta_last_64;
int16_t nb_sect_64;
// ----------------
// LEADING strand
// ----------------
for (const auto& cds: gen_unit->protein_list(LEADING))
{
// Alpha : angles from OriC (in degrees)
// Theta : angles on the trigonometric circle (in degrees)
// nb_sect : "length" in degrees of the arc to be drawn
alpha_first = (int16_t) round(360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last = (int16_t) round(360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first = Utils::mod(90 - alpha_first, 360);
// theta_last = Utils::mod(90 - alpha_last, 360);
nb_sect = Utils::mod(alpha_last - alpha_first + 1, 360);
// These are the same as above but with a higher precision (1/64 degrees)
alpha_first_64 = (int16_t) round(64 * 360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last_64 = (int16_t) round(64 * 360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first_64 = Utils::mod(64 * 90 - alpha_first_64, 64 * 360);
// theta_last_64 = Utils::mod(64 * 90 - alpha_last_64, 64 * 360);
nb_sect_64 = Utils::mod(alpha_last_64 - alpha_first_64 + 1, 64 * 360);
// Look for the inmost layer that has all the sectors between
// theta_first and theta_last free
int16_t layer = 0;
bool sectors_free = false;
while (! sectors_free)
{
sectors_free = true;
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
if (occupied_sectors_[LEADING][layer][Utils::mod(theta_first-rho, 360)])
{
sectors_free = false;
break;
}
}
if (sectors_free)
{
break; // All the needed sectors are free on the current layer
}
else
{
layer++;
if (layer >= outmost_layer_)
{
add_layer();
break; // An added layer is necessarily free, no need to look further
}
}
}
// Mark sectors to be drawn as occupied
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
occupied_sectors_[LEADING][layer][Utils::mod(theta_first-rho, 360)] = true;
}
// Mark flanking sectors as occupied
occupied_sectors_[LEADING][layer][Utils::mod(theta_first+1, 360)] = true;
occupied_sectors_[LEADING][layer][Utils::mod(theta_first-nb_sect, 360)] = true;
// Draw
const int8_t cds_layer_spacing = 5; // TODO : param?
layer++; // index starting at 0 but needed to start at 1
int16_t diam2 = diam + (layer * 2 * cds_layer_spacing);
pos_x = canvas_width + (int16_t) round((double)(canvas_width - diam2) / 2.0);
pos_y = (int16_t) round((double)(canvas_height - diam2) / 2.0);
char* color = X11Window::color(cds.mean());
win->draw_arc_64(pos_x, pos_y, diam2, theta_first_64 - nb_sect_64, nb_sect_64, color);
delete [] color;
}
// ----------------
// LAGGING strand
// ----------------
for (const auto& cds: gen_unit->protein_list(LAGGING))
{
// Alpha : angles from OriC (in degrees)
// Theta : angles on the trigonometric circle (in degrees)
// nb_sect : "length" in degrees of the arc to be drawn
alpha_first = (int16_t) round(360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last = (int16_t) round(360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first = Utils::mod(90 - alpha_first, 360);
// theta_last = Utils::mod(90 - alpha_last, 360);
nb_sect = Utils::mod(alpha_first - alpha_last + 1, 360);
// These are the same as above but with a higher precision (1/64 degrees)
alpha_first_64 = (int16_t) round(64 * 360 * ((double)cds.first_translated_pos() / (double)genome_length));
alpha_last_64 = (int16_t) round(64 * 360 * ((double)cds.last_translated_pos() / (double)genome_length));
theta_first_64 = Utils::mod(64 * 90 - alpha_first_64, 64 * 360);
// theta_last_64 = Utils::mod(64 * 90 - alpha_last_64, 64 * 360);
nb_sect_64 = Utils::mod(alpha_first_64 - alpha_last_64 + 1, 64 * 360);
// Look for the inmost layer that has all the sectors between
// theta_first and theta_last free
int16_t layer = 0;
bool sectors_free = false;
while (! sectors_free)
{
sectors_free = true;
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
if (occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+rho, 360)])
{
sectors_free = false;
break;
}
}
if (sectors_free)
{
break; // All the needed sectors are free on the current layer
}
else
{
layer++;
if (layer >= outmost_layer_)
{
add_layer();
break; // An added layer is necessarily free, no need to look further
}
}
}
// Mark sectors to be drawn as occupied
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+rho, 360)] = true;
}
// Mark flanking sectors as occupied
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first-1, 360)] = true;
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+nb_sect, 360)] = true;
// Draw
const int8_t cds_layer_spacing = 5; // TODO : param?
layer++; // index starting at 0 but needed to start at 1
int16_t diam2 = diam - (layer * 2 * cds_layer_spacing);
pos_x = canvas_width + (int16_t) round((double)(canvas_width - diam2) / 2.0);
pos_y = (int16_t) round((double)(canvas_height - diam2) / 2.0);
char* color = X11Window::color(cds.mean());
win->draw_arc_64(pos_x, pos_y, diam2, theta_first_64, nb_sect_64, color);
delete [] color;
}
}
}
void Individual_X11::display_rnas(X11Window * win)
{
// Retreive the genetic unit corresponding to the main chromosome
const GeneticUnit* gen_unit = &genetic_unit_list_.front();
int32_t genome_length = gen_unit->dna()->length();
// Display the number of RNAs
char nb_rna[40];
sprintf(nb_rna, "Leading : %" PRId32 " RNAs", static_cast<int32_t>(gen_unit->rna_list()[LEADING].size()));
win->draw_string(15, 15, nb_rna);
sprintf(nb_rna, "Lagging : %" PRId32 " RNAs", static_cast<int32_t>(gen_unit->rna_list()[LAGGING].size()));
win->draw_string(15, 30, nb_rna);
// Compute display diameter according to genome length and window size
int16_t win_size = Utils::min(win->width(), win->height());
int16_t diam = round(win_size * log((double)genome_length) / 16);
// Prevent diameter from getting greater than 2/3 of the window size
if (diam > 2 * win_size / 3)
{
diam = 2 * win_size / 3;
}
// Compute coordinates of the upper-left corner of the containing square
int16_t pos_x = (win->width() - diam) / 2;
int16_t pos_y = (win->height() - diam) / 2;
// Draw main circle
win->draw_circle(pos_x, pos_y, diam);
// Sector occupation management
reset_sectors();
// ---------------
// Draw each RNA
// ---------------
// NB : As we want OriC to be at the "top" of the circle and the orientation
// to be clockwise, the drawing angle (theta) will be given as
// (90 - alpha), alpha being the "classical" trigonometric angle
int16_t alpha_first, alpha_last; // Angles of first and last transcribed bases from OriC (degrees)
int16_t theta_first, theta_last; // Transposed angles on the trigonometric circle (degrees)
int16_t nb_sect;
// Same as above with precision = 1/64 degree
int16_t alpha_first_64, alpha_last_64;
int16_t theta_first_64, theta_last_64;
int16_t nb_sect_64;
// ----------------
// LEADING strand
// ----------------
const auto& rna_lists = gen_unit->rna_list();
for (const auto& rna: rna_lists[LEADING])
{
// Alpha : angles from OriC (in degrees)
// Theta : angles on the trigonometric circle (in degrees)
// nb_sect : "length" in degrees of the arc to be drawn
alpha_first = (int16_t) round(360 * ((double)rna.first_transcribed_pos() / (double)genome_length));
alpha_last = (int16_t) round(360 * ((double)rna.last_transcribed_pos() / (double)genome_length));
theta_first = Utils::mod(90 - alpha_first, 360);
theta_last = Utils::mod(90 - alpha_last, 360);
nb_sect = Utils::mod(alpha_last - alpha_first + 1, 360);
// These are the same as above but with a higher precision (1/64 degrees)
alpha_first_64 = (int16_t) round(64 * 360 * ((double)rna.first_transcribed_pos() / (double)genome_length));
alpha_last_64 = (int16_t) round(64 * 360 * ((double)rna.last_transcribed_pos() / (double)genome_length));
theta_first_64 = Utils::mod(64 * 90 - alpha_first_64, 64 * 360);
theta_last_64 = Utils::mod(64 * 90 - alpha_last_64, 64 * 360);
nb_sect_64 = Utils::mod(alpha_last_64 - alpha_first_64 + 1, 64 * 360);
//~ printf(" LEADING RNA %"PRId32" => %"PRId32" :: %"PRId16" %"PRId16"\n", rna->first_transcribed_pos(), rna->last_transcribed_pos(), theta_first, theta_last);
// Look for the inmost layer that has all the sectors between
// theta_first and theta_last free
int16_t layer = 0;
bool sectors_free = false;
while (! sectors_free)
{
sectors_free = true;
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
if (occupied_sectors_[LEADING][layer][Utils::mod(theta_first-rho, 360)])
{
sectors_free = false;
break;
}
}
if (sectors_free)
{
break; // All the needed sectors are free on the current layer
}
else
{
layer++;
if (layer >= outmost_layer_)
{
add_layer();
break; // An added layer is necessarily free, no need to look further
}
}
}
// Mark sectors to be drawn as occupied
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
occupied_sectors_[LEADING][layer][Utils::mod(theta_first-rho, 360)] = true;
}
// Mark flanking sectors as occupied
occupied_sectors_[LEADING][layer][Utils::mod(theta_first+1, 360)] = true;
occupied_sectors_[LEADING][layer][Utils::mod(theta_first-nb_sect, 360)] = true;
// Determine drawing color
char* color;
if (rna.is_coding())
{
color = X11Window::color(rna.basal_level());
}
else
{
color = new char[8];
strcpy(color, "#FFFFFF");
}
// Draw arrow body
const int8_t rna_layer_spacing = 5; // TODO : param?
layer++; // index starting at 0 but needed to start at 1
int16_t diam2 = diam + (layer * 2 * rna_layer_spacing);
pos_x = (int16_t) round((double)(win->width() - diam2) / 2.0);
pos_y = (int16_t) round((double)(win->height() - diam2) / 2.0);
win->draw_arc_64(pos_x, pos_y, diam2, theta_first_64 - nb_sect_64, nb_sect_64, color);
// Draw arrow head
int8_t arrow_thick = 6; // Must be an even value
pos_x = (win->width() / 2.0) + (cos((theta_first_64 - nb_sect_64)/(64*180.0)*M_PI) * diam2 / 2.0) - (arrow_thick / 2.0);
pos_y = (win->height() / 2.0) - (sin((theta_first_64 - nb_sect_64)/(64*180.0)*M_PI) * diam2 / 2.0) - (arrow_thick / 2.0);
win->fill_arc(pos_x, pos_y, arrow_thick, Utils::mod(180+theta_last, 360), 180, color);
delete [] color;
}
// ----------------
// LAGGING strand
// ----------------
for (const auto& rna: rna_lists[LAGGING]) {
// Alpha : angles from OriC (in degrees)
// Theta : angles on the trigonometric circle (in degrees)
// nb_sect : "length" in degrees of the arc to be drawn
alpha_first = (int16_t) round(360 * ((double)rna.first_transcribed_pos() / (double)genome_length));
alpha_last = (int16_t) round(360 * ((double)rna.last_transcribed_pos() / (double)genome_length));
theta_first = Utils::mod(90 - alpha_first, 360);
theta_last = Utils::mod(90 - alpha_last, 360);
nb_sect = Utils::mod(alpha_first - alpha_last + 1, 360);
// These are the same as above but with a higher precision (1/64 degrees)
alpha_first_64 = (int16_t) round(64 * 360 * ((double)rna.first_transcribed_pos() / (double)genome_length));
alpha_last_64 = (int16_t) round(64 * 360 * ((double)rna.last_transcribed_pos() / (double)genome_length));
theta_first_64 = Utils::mod(64 * 90 - alpha_first_64, 64 * 360);
theta_last_64 = Utils::mod(64 * 90 - alpha_last_64, 64 * 360);
nb_sect_64 = Utils::mod(alpha_first_64 - alpha_last_64 + 1, 64 * 360);
//~ printf(" LAGGING RNA %"PRId32" => %"PRId32" :: %"PRId16" %"PRId16"\n", rna->first_transcribed_pos(), rna->last_transcribed_pos(), theta_first, theta_last);
// Look for the inmost layer that has all the sectors between
// theta_first and theta_last free
int16_t layer = 0;
bool sectors_free = false;
while (! sectors_free)
{
sectors_free = true;
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
if (occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+rho, 360)])
{
sectors_free = false;
break;
}
}
if (sectors_free)
{
break; // All the needed sectors are free on the current layer
}
else
{
layer++;
if (layer >= outmost_layer_)
{
add_layer();
break; // An added layer is necessarily free, no need to look further
}
}
}
// Mark sectors to be drawn as occupied
for (int16_t rho = 0 ; rho < nb_sect ; rho++)
{
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+rho, 360)] = true;
}
// Mark flanking sectors as occupied
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first-1, 360)] = true;
occupied_sectors_[LAGGING][layer][Utils::mod(theta_first+nb_sect, 360)] = true;
// Determine drawing color
char* color;
if (rna.is_coding())
{
color = X11Window::color(rna.basal_level());
}
else
{
color = new char[8];
strcpy(color, "#FFFFFF");
}
// Draw arrow body
const int8_t rna_layer_spacing = 5; // TODO : param?
layer++; // index starting at 0 but needed to start at 1
int16_t diam2 = diam - (layer * 2 * rna_layer_spacing);
pos_x = (int16_t) round((double)(win->width() - diam2) / 2.0);
pos_y = (int16_t) round((double)(win->height() - diam2) / 2.0);
win->draw_arc_64(pos_x, pos_y, diam2, theta_first_64, nb_sect_64, color);
// Draw arrow head
int8_t arrow_thick = 6; // Must be an even value
pos_x = (win->width() / 2.0) + (cos((theta_last_64+1)/(64*180.0)*M_PI) * diam2 / 2.0) - (arrow_thick / 2.0);
pos_y = (win->height() / 2.0) - (sin((theta_last_64+1)/(64*180.0)*M_PI) * diam2 / 2.0) - (arrow_thick / 2.0);
win->fill_arc(pos_x, pos_y, arrow_thick, theta_last, 180, color);
delete [] color;
}
}
// =================================================================
// Protected Methods
// =================================================================
void Individual_X11::add_layer()
{
occupied_sectors_[LEADING][outmost_layer_] = new bool[360];
occupied_sectors_[LAGGING][outmost_layer_] = new bool[360];
for (int16_t angle = 0 ; angle < 360 ; angle++)
{
occupied_sectors_[LEADING][outmost_layer_][angle] = false;
occupied_sectors_[LAGGING][outmost_layer_][angle] = false;
}
outmost_layer_++;
}
void Individual_X11::init_occupied_sectors()
{
outmost_layer_ = 1;
for (int16_t layer = 0 ; layer < outmost_layer_ ; layer++)
{
occupied_sectors_[LEADING][layer] = new bool[360];
occupied_sectors_[LAGGING][layer] = new bool[360];
}
}
void Individual_X11::reset_sectors()
{
for (int16_t layer = 0 ; layer < outmost_layer_ ; layer++)
{
for (int16_t angle = 0 ; angle < 360 ; angle++)
{
occupied_sectors_[LEADING][layer][angle] = false;
occupied_sectors_[LAGGING][layer][angle] = false;
}
}
}
} // namespace aevol