//
// Created by alberto on 03/05/23.
//
#include "sectionH.h"
#include <vector>
const double sectionH::PI = 3.14159265358979323846;
sectionH::sectionH(nsol::NeuronMorphologySection* _sec){
sec=_sec;
selecionada=false;
getTamSection();
coordX=0;
coordY=0;
displacementX=0;
displacementY=0;
seleccionada_primera=false;
for(nsol::Section* s : sec->children()){
nsol::NeuronMorphologySection* section = dynamic_cast<nsol::NeuronMorphologySection*>(s);
sectionsHijas.push_back(new sectionH(section));
}
tamSeccion=getTamSection();
tamPuntoInicialPuntoFinal=getTamPuntoInicialPuntoFinal();
}
float sectionH::getTamTotal(float *max, float *min){
float tam=0;
for (sectionH* s : sectionsHijas) {
tam+=s->getTamTotal(max,min);
}
tam+=getTamSection();
if(getTamSection()>(*max))
(*max)=getTamSection();
else if (getTamSection()<(*min))
(*min)=getTamSection();
return tam;
}
float sectionH::getTamSection(){
nsol::Node* s=sec->firstNode();
nsol::Node* a;
bool first=true;
float tam=0.0f;
for(nsol::Node* node:sec->nodes()){
if(first)
first=false;
else{
a=s;
s=node;
tam+= distanciaEntreRegistros(s,a);
}
}
return tam;
}
float sectionH::getVolumenAcumulado(float *maxVolumenSeccion,float *minVolumenSeccion){
float vol=0;
for (sectionH* s : sectionsHijas) {
vol+=s->getVolumenAcumulado(maxVolumenSeccion,minVolumenSeccion);
}
vol+=getVolumenSeccion();
if(getVolumenSeccion()>(*maxVolumenSeccion))
(*maxVolumenSeccion)=getVolumenSeccion();
else if (getVolumenSeccion()<(*minVolumenSeccion))
(*minVolumenSeccion)=getVolumenSeccion();
return vol;
}
float sectionH::getVolumenSeccion(){
nsol::Node* s=sec->firstNode();
nsol::Node* a;
bool first=true;
float tam=0.0f;
for(nsol::Node* node:sec->nodes()){
if(first)
first=false;
else{
a=s;
s=node;
tam+= volumenCono(s,a);
}
}
return tam;
}
float sectionH::distanciaEntreRegistros(nsol::Node* r1, nsol::Node* r2){
return std::sqrt( std::pow(r1->point()[0] - r2->point()[0], 2) +
std::pow(r1->point()[1] - r2->point()[1], 2) +
std::pow(r1->point()[2] - r2->point()[2], 2));
}
float sectionH::areaCono(nsol::Node* r1,nsol::Node* r2){
double r=std::abs(r1->radius()-r2->radius());
double g=std::sqrt(r*r+std::pow(r1->point()[0] - r2->point()[0], 2) +
std::pow(r1->point()[1] - r2->point()[1], 2) +
std::pow(r1->point()[2] - r2->point()[2], 2));
return PI*g*(r1->radius()+r2->radius());
}
float sectionH::volumenCono(nsol::Node* r1,nsol::Node* r2) {
double h=distanciaEntreRegistros(r1,r2);
return (PI/3.)*h*(std::pow(r1->radius(),2)+std::pow(r2->radius(),2)+r1->radius()*r2->radius());
}
nsol::NeuronMorphologySection *sectionH::getSection(){
return sec;
}
void sectionH::drawSectionsTree(float x1, float x2, float angle, float hipotenusa, float dif_angle, bool g, float max, float min, VarEstado variable_grosor){
float valorX,valorY,valorX2,valorY2;
coordX=x1;
coordY=x2;
hipotenusa*=0.8;
valorX=x1+cos(angle-1.30899694*dif_angle)*hipotenusa;
valorY=x2+sin(angle-1.30899694*dif_angle)*hipotenusa;
valorX2=x1+cos(angle+1.30899694*dif_angle)*hipotenusa;
valorY2=x2+sin(angle+1.30899694*dif_angle)*hipotenusa;
dif_angle*=0.6;
int i=0;
for (sectionH* s : sectionsHijas) {
if(i==0){
if(g) {
getLineWidth( variable_grosor, *s, max, min);
}
drawLine(x1,x2,valorX,valorY);
drawPoint(valorX,valorY);
s->drawSectionsTree(valorX,valorY,angle,hipotenusa,dif_angle,g,max,min,variable_grosor);
}
else{
if(g) {
getLineWidth( variable_grosor, *s, max, min);
}
drawLine(x1,x2,valorX2,valorY2);
drawPoint(valorX2,valorY2);
s->drawSectionsTree(valorX2,valorY2,angle,hipotenusa,dif_angle,g,max,min,variable_grosor);
}
i++;
}
}
bool sectionH::selected(QOpenGLWidget* windowPaint,float x, float y) {
if(coordX + 0.01 > x && coordX - 0.01 < x && coordY + 0.01 > y && coordY - 0.01 < y){
QString texto="Soy la seleccionada ";
seeToolTip(texto,windowPaint);
seleccionada_primera=true;
selected_hijas(true);
return true;
}
else{
seleccionada_primera=false;
selected_hijas(false);
}
if (sectionsHijas.size() == 2) {
bool a=sectionsHijas[0]->selected(windowPaint,x,y);
if (a)
return true;
else
return sectionsHijas[1]->selected(windowPaint,x,y);
}
else
return false;
}
/* drawSectionsDendograma()
* elegirSeccionPrimeraYSegunda();
* calcularPuntosSeccionPrimera();
* drawSeccionRecta();
* llamadaRecursiva();
* calcularPuntosSeccionSEgunda();
* drawArco();
* drawSeccion2();
* llamadaRecursiva();
*
*
*/
void sectionH::drawSectionsDendograma(float x, float y, float angle_hueco, float angle, float terminal_nodes, int *cont, bool g,
float max, float min, VarEstado variable_grosor, VarLongitud var_long, float max_long, float min_long) {
coordX=x;
coordY=y;
if (sectionsHijas.size() == 2) {
sectionH *sec1, *sec2;
//ahora mismo se va siempre por la rama más grande, con una variable de estado podriamos decidir si lo queremos asi o queremos que siga el camino que nos dan
if (sectionsHijas[0]->terminalNodes() > sectionsHijas[1]->terminalNodes()) {
sec1 = sectionsHijas[0];
sec2 = sectionsHijas[1];
} else {
sec1 = sectionsHijas[1];
sec2 = sectionsHijas[0];
}
if (g) {
getLineWidth(variable_grosor, *sec1, max, min);
}
float x2;
float y2;
x2 = x+ sec1->getPoint2(var_long,max_long,min_long) * cos(angle - angle_hueco * (*cont) / terminal_nodes);
y2 =y+ sec1->getPoint2(var_long,max_long,min_long) * sin(angle - angle_hueco * (*cont) / terminal_nodes);
drawLine(x, y, x2, y2);
drawPoint(x2, y2);
sec1->drawSectionsDendograma(x2, y2, angle_hueco, angle, terminal_nodes, cont,
g, max, min, variable_grosor,var_long,max_long,min_long);
(*cont)++;
float modulo = sqrt(pow(x - displacementX, 2) + pow(y - displacementY, 2));
float nx = modulo * cos(angle - angle_hueco * (*cont) / terminal_nodes) + displacementX;
float ny = modulo * sin(angle - angle_hueco * (*cont) / terminal_nodes) + displacementY;
float nix = sec2->getPoint2(var_long,max_long,min_long) * cos(angle - angle_hueco * (*cont) / terminal_nodes);
float niy = sec2->getPoint2(var_long,max_long,min_long) * sin(angle - angle_hueco * (*cont) / terminal_nodes);
drawArco( x, y, nx, ny, angle, angle_hueco,cont, terminal_nodes, modulo);
if (g) {
getLineWidth( variable_grosor,*sec2, max, min);
}
drawLine(nx,ny,nx+nix,ny+niy);
drawPoint(nx+nix,ny+niy);
sec2->drawSectionsDendograma(nx + nix, ny + niy, angle_hueco, angle, terminal_nodes, cont, g, max,
min, variable_grosor,var_long,max_long,min_long);
}
}
void sectionH::drawSectionsEsquema(float x, float y, float terminal_nodes) {
coordX = x;
coordY = y;
glBegin(GL_LINES);
glColor3f(0.7f, 0.5f, 0.2f);
float calcX, calcY;
switch (static_cast<int>(terminal_nodes)) {
case 1: // Dibujar una neurona con una pata
for (float i = 0; i < 10; i += 0.01) {
calcX = 0.5 * cos(i);
calcY = 0.5 * sin(i);
glVertex2f(calcX + displacementX + x, calcY + displacementY + y);
}
break;
case 2: // Dibujar una neurona con dos patas
// Falta implementación
break;
//Resto de casos
default:
// En caso de un valor no válido, simplemente dibujar un círculo
for (float i = 0; i < 10; i += 0.01) {
calcX = 0.5 * cos(i);
calcY = 0.5 * sin(i);
glVertex2f(calcX + displacementX + x, calcY + displacementY + y);
}
break;
}
glEnd();
}
float sectionH::terminalNodes() {
float terminal=0;
if(sectionsHijas.empty()){
terminal++;
}
for (sectionH* s : sectionsHijas) {
terminal+=s->terminalNodes();
}
return terminal;
}
void sectionH::drawArco(float x1,float y1,float x2,float y2,float angle,float angle_hueco, int* cont,float terminal_nodes,float modulo){
glLineWidth(1);
glBegin(GL_LINES);
glColor3f(1.0, 1.0, 1.0);
float angle_aux = std::atan2(y1-displacementY, x1-displacementX);
if (angle_aux < angle - angle_hueco * (*cont)/terminal_nodes)
angle_aux += 2 * 3.14159;
glVertex2f(x1, y1);
for (float i = angle_aux; i >= angle - angle_hueco * (*cont) / terminal_nodes; i -= 0.005) {
float xAux = modulo * cos(i) ; // Calcula la coordenada x
float yAux = modulo * sin(i) ; // Calcula la coordenada y
glVertex2f(xAux + displacementX, yAux + displacementY); // Dibuja el vértice en la posición (x + cx, y + cy)
glVertex2f(xAux + displacementX, yAux + displacementY); // Dibuja el vértice en la posición (x + cx, y + cy)
}
glVertex2f(x2, y2);
glEnd();
}
void sectionH::drawLine(float x1,float y1,float x2,float y2){
glBegin(GL_LINES);
glColor3f(1.0, 1.0, 1.0);
glVertex2f(x1, y1);
glVertex2f(x2, y2);
glEnd();
}
void sectionH::drawPoint(float x1,float y1){
glPointSize(5.0);
glBegin(GL_POINTS);
glColor3f(color.x(), color.y(), color.z());
glVertex2f(x1, y1);
glEnd();
}
void sectionH::getLineWidth(VarEstado variable_grosor, sectionH sec, float max, float min){
float aux, n;
switch (variable_grosor) {
case VarEstado::Volumen:
aux = (sec.getVolumenSeccion() - min) / (max - min);
break;
case VarEstado::nodosTerminales:
aux = (sec.terminalNodes() - min) / (max - min);
break;
case VarEstado::Tamano:
aux = (sec.getTamSection() - min) / (max - min);
break;
}
n = aux * 4 + 1;
glLineWidth(n);
}
float sectionH::getPoint2(VarLongitud var_long, float max, float min){
switch (var_long) {
case VarLongitud::TamanoSeccion:
return (tamSeccion-min)/(max-min)*1.4;
case VarLongitud::TamanoPuntoInitPuntoFinal:
return (tamPuntoInicialPuntoFinal-min)/(max-min)*1.4;
case VarLongitud::unitario:
return max;
default:
return max;
}
}
void sectionH::coordinates() {
}
void sectionH::seeToolTip(QString texto,QOpenGLWidget *windowPaint){
QToolTip::showText(QCursor::pos(), texto, windowPaint, QRect(), 500);
}
void sectionH::draw3d( float x, float y, float z) {
if(seleccionada_primera){
glPointSize(10.0);
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(sec->lastNode()->point()[0]/100,sec->lastNode()->point()[1]/100,sec->lastNode()->point()[2]/100);
glEnd();
}
glBegin(GL_LINES);
if(selecionada){
glColor3f(1,1,1);
}
else{
glColor3f(x, y, z);
}
for(nsol::Node* n: sec->nodes()){
if(n==sec->firstNode() || n==sec->lastNode())
glVertex3f(n->point()[0]/100,n->point()[1]/100,n->point()[2]/100);
else{
glVertex3f(n->point()[0]/100,n->point()[1]/100,n->point()[2]/100);
glVertex3f(n->point()[0]/100,n->point()[1]/100,n->point()[2]/100);
}
}
glEnd();
for(sectionH *s: sectionsHijas){
s->draw3d(x,y,z);
}
}
void sectionH::selected_hijas(bool sel) {
selecionada=sel;
for(sectionH* s:sectionsHijas){
s->selected_hijas(sel);
}
}
void sectionH::setDisplacementX(float displacementX) {
sectionH::displacementX = displacementX;
for (sectionH* s :sectionsHijas)
s->setDisplacementX(displacementX);
}
void sectionH::setDisplacementY(float displacementY) {
sectionH::displacementY = displacementY;
for (sectionH* s :sectionsHijas)
s->setDisplacementY(displacementY);
}
void sectionH::putColor(Eigen::Vector3f c) {
color=c;
for (sectionH* s :sectionsHijas)
s->putColor(c);
}
float sectionH::getTamPuntoInicialPuntoFinal() {
nsol::Node* s=sec->firstNode();
nsol::Node* a=sec->lastNode();
float dist=distanciaEntreRegistros(s,a);
return dist;
}
void sectionH::getTamTotalP1P2(float *max, float *min) {
float vol=0;
for (sectionH* s : sectionsHijas) {
s->getTamTotalP1P2(max, min);
}
if(getTamPuntoInicialPuntoFinal()>(*max))
(*max)=getTamPuntoInicialPuntoFinal();
else if (getTamPuntoInicialPuntoFinal()<(*min))
(*min)=getTamPuntoInicialPuntoFinal();
}
nsol::NeuronMorphologySection *sectionH::getSec() const {
return sec;
}
void
sectionH::drawSol(float x, float y, float angle_hueco, float angle, float terminal_nodes, int *cont, bool g, float max,
float min, VarEstado variable_grosor) {
coordX=x;
coordY=y;
if (sectionsHijas.size() == 2) {
sectionH *sec1, *sec2;
//ahora mismo se va siempre por la rama más grande, con una variable de estado podriamos decidir si lo queremos asi o queremos que siga el camino que nos dan
if (sectionsHijas[0]->terminalNodes() > sectionsHijas[1]->terminalNodes()) {
sec1 = sectionsHijas[0];
sec2 = sectionsHijas[1];
} else {
sec1 = sectionsHijas[1];
sec2 = sectionsHijas[0];
}
if (g) {
getLineWidth(variable_grosor, *sec1, max, min);
}
float x2;
float y2;
Eigen::Vector3f na(0,0,0);
float dist= distanciaEntreRegistrosV(na, sec1->getSection()->lastNode()->point());
x2 = dist * cos(angle - angle_hueco * (*cont) / terminal_nodes);
y2 = dist * sin(angle - angle_hueco * (*cont) / terminal_nodes);
drawLine(x, y, x2, y2);
drawPoint(x2, y2);
sec1->drawSol(x2, y2, angle_hueco, angle, terminal_nodes, cont,
g, max, min, variable_grosor);
(*cont)++;
float modulo = sqrt(pow(x - displacementX, 2) + pow(y - displacementY, 2));
float nx = modulo * cos(angle - angle_hueco * (*cont) / terminal_nodes) + displacementX;
float ny = modulo * sin(angle - angle_hueco * (*cont) / terminal_nodes) + displacementY;
float dist2= distanciaEntreRegistrosV(na, sec2->getSection()->lastNode()->point());
float nix = dist2 * cos(angle - angle_hueco * (*cont) / terminal_nodes);
float niy = dist2 * sin(angle - angle_hueco * (*cont) / terminal_nodes);
drawArco( x, y, nx, ny, angle, angle_hueco,cont, terminal_nodes, modulo);
if (g) {
getLineWidth( variable_grosor,*sec2, max, min);
}
drawLine(nx,ny,nix,niy);
drawPoint(nix,niy);
sec2->drawSol(nix, niy, angle_hueco, angle, terminal_nodes, cont, g, max,
min, variable_grosor);
}
}
float sectionH::distanciaEntreRegistrosV(Eigen::Vector3f r1, Eigen::Vector3f r2){
return std::sqrt( std::pow(r1[0] - r2[0]/100, 2) +
std::pow(r1[1] - r2[1]/100, 2) +
std::pow(r1[2] - r2[2]/100, 2));
}
void sectionH::cont_points_neu(int *aux, float separador,float crecimiento) {
Eigen::Vector3f na(0,0,0);
float valor= distanciaEntreRegistrosV(na,sec->firstNode()->point());
int i=0;
bool encontrado=false;
float sep=separador;
do{
if(valor<sep){
encontrado=true;
aux[i]=aux[i]+1;
}
sep+=crecimiento;
i++;
} while(i<8 && !encontrado);
if(!encontrado){
aux[8]=aux[8]+1;
}
if (sectionsHijas.size() == 2) {
sectionsHijas[0]->cont_points_neu(aux,separador,crecimiento);
sectionsHijas[1]->cont_points_neu(aux,separador,crecimiento);
}
}