Skip to content

Commit 1823b11

Browse files
committed
Merge branch 'master' into fixes_L
2 parents 137ded7 + 4f26bdc commit 1823b11

File tree

2 files changed

+157
-24
lines changed

2 files changed

+157
-24
lines changed

src/Core/Algorithms/BrainStimulator/ElectrodeCoilSetupAlgorithm.cc

Lines changed: 153 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const AlgorithmInputName ElectrodeCoilSetupAlgorithm::LOCATIONS("LOCATIONS");
8686
const int ElectrodeCoilSetupAlgorithm::unknown_stim_type = 0;
8787
const int ElectrodeCoilSetupAlgorithm::TMS_stim_type = 1;
8888
const int ElectrodeCoilSetupAlgorithm::tDCS_stim_type = 2;
89+
const double ElectrodeCoilSetupAlgorithm::direction_bound = -0.99;
8990

9091
const AlgorithmParameterName ElectrodeCoilSetupAlgorithm::columnNames[] =
9192
{ Name("Input #"),
@@ -425,7 +426,7 @@ FieldHandle ElectrodeCoilSetupAlgorithm::make_tms(FieldHandle scalp, const std::
425426
if (fielddata->ncols()!=3)
426427
{
427428
std::ostringstream ostr4;
428-
ostr4 << " Trying to generate magnetic dipoles for TMS coil defined in table row " << i << " could not find any prototyp normals - using (NX,NY,NZ) from GUI instead! " << std::endl;
429+
ostr4 << " Trying to generate magnetic dipoles for TMS coil defined in table row " << i+1 << " could not find any prototyp normals - using (NX,NY,NZ) from GUI instead! " << std::endl;
429430
remark(ostr4.str());
430431
}
431432
}
@@ -442,7 +443,16 @@ FieldHandle ElectrodeCoilSetupAlgorithm::make_tms(FieldHandle scalp, const std::
442443
Point vec((*magnetic_dipoles)(j,0),(*magnetic_dipoles)(j,1),(*magnetic_dipoles)(j,2));
443444
tms_coils_field_values.push_back(vec);
444445
}
445-
}
446+
} else
447+
{
448+
std::ostringstream ostr3;
449+
ostr3 << " TMS coil definition for " << i+1 << ". row needs be a point cloud (with defined scalar or vectors data)." << std::endl;
450+
remark(ostr3.str());
451+
continue;
452+
}
453+
} else
454+
{
455+
THROW_ALGORITHM_PROCESSING_ERROR("Internal error: coil definition inconsistent. ");
446456
}
447457
}
448458

@@ -462,7 +472,96 @@ FieldHandle ElectrodeCoilSetupAlgorithm::make_tms(FieldHandle scalp, const std::
462472
return tms_coils_field;
463473
}
464474

465-
boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgorithm::make_tdcs_electrodes(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto, const std::vector<double>& elc_prototyp_map, const std::vector<double>& elc_x, const std::vector<double>& elc_y, const std::vector<double>& elc_z, const std::vector<double>& elc_angle_rotation, const std::vector<double>& elc_thickness) const
475+
boost::tuple<Variable::List,double, double, double> ElectrodeCoilSetupAlgorithm::make_table_row(int i, double x, double y, double z, double nx, double ny, double nz) const
476+
{
477+
Variable::List tmp;
478+
double out_nx, out_ny, out_nz;
479+
auto tab_values = get(Parameters::TableValues).toVector();
480+
auto col = tab_values[i].toVector();
481+
std::string str1=col[0].toString();
482+
std::string str2=col[1].toString();
483+
std::string str3=col[2].toString();
484+
std::string str4=col[3].toString();
485+
std::string str5=col[4].toString();
486+
std::string str6=col[5].toString();
487+
488+
std::string str7=col[6].toString();
489+
std::string str8=col[7].toString();
490+
std::string str9=col[8].toString();
491+
492+
std::string str10=col[9].toString();
493+
494+
if (str7.compare("???")==0)
495+
{
496+
str7 = boost::str(boost::format("%.3f") % nx);
497+
out_nx=nx;
498+
} else
499+
{
500+
try
501+
{
502+
out_nx = boost::lexical_cast<double>(col[6].toString());
503+
} catch(bad_lexical_cast&) { }
504+
}
505+
506+
if (str8.compare("???")==0)
507+
{
508+
str8 = boost::str(boost::format("%.3f") % ny);
509+
out_ny=ny;
510+
} else
511+
{
512+
try
513+
{
514+
out_ny = boost::lexical_cast<double>(col[7].toString());
515+
} catch(bad_lexical_cast&) { }
516+
}
517+
518+
if (str9.compare("???")==0)
519+
{
520+
str9 = boost::str(boost::format("%.3f") % nz);
521+
out_nz=nz;
522+
} else
523+
{
524+
try
525+
{
526+
out_nz = boost::lexical_cast<double>(col[8].toString());
527+
} catch(bad_lexical_cast&) { }
528+
}
529+
530+
Variable var1=makeVariable("Input #", boost::str(boost::format("%s") % str1));
531+
Variable var2=makeVariable("Type", boost::str(boost::format("%s") % str2));
532+
533+
Variable var3,var4,var5;
534+
535+
if (str3.compare("???")==0)
536+
var3=makeVariable("X", boost::str(boost::format("%.3f") % x));
537+
else
538+
var3=makeVariable("X", boost::str(boost::format("%s") % str3));
539+
540+
if (str4.compare("???")==0)
541+
var4=makeVariable("Y", boost::str(boost::format("%.3f") % y));
542+
else
543+
var4=makeVariable("Y", boost::str(boost::format("%s") % str4));
544+
545+
if (str5.compare("???")==0)
546+
var5=makeVariable("Y", boost::str(boost::format("%.3f") % z));
547+
else
548+
var5=makeVariable("Z", boost::str(boost::format("%s") % str5));
549+
550+
Variable var6=makeVariable("Angle", boost::str(boost::format("%s") % str6));
551+
552+
///if this table row was selected as tDCS -> project point to scalp surface and put its normal in table (NX,NY,NZ)
553+
Variable var7=makeVariable("NX", boost::str(boost::format("%s") % str7));
554+
Variable var8=makeVariable("NY", boost::str(boost::format("%s") % str8));
555+
Variable var9=makeVariable("NZ", boost::str(boost::format("%s") % str9));
556+
557+
Variable var10=makeVariable("thickness",boost::str(boost::format("%s") % str10));
558+
tmp += var1,var2,var3,var4,var5,var6,var7,var8,var9,var10;
559+
560+
return boost::make_tuple(tmp, out_nx, out_ny, out_nz);
561+
}
562+
563+
564+
boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle, VariableHandle> ElectrodeCoilSetupAlgorithm::make_tdcs_electrodes(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto, const std::vector<double>& elc_prototyp_map, const std::vector<double>& elc_x, const std::vector<double>& elc_y, const std::vector<double>& elc_z, const std::vector<double>& elc_angle_rotation, const std::vector<double>& elc_thickness, VariableHandle table) const
466565
{
467566
int nr_elc_sponge_triangles=0, num_valid_electrode_definition=0, nr_elc_sponge_triangles_on_scalp=0;
468567
std::vector<double> field_values, field_values_elc_on_scalp;
@@ -475,9 +574,11 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
475574
FieldHandle output = CreateField(fieldinfo3);
476575
VMesh* output_vmesh = output->vmesh();
477576
VField* output_vfld = output->vfield();
478-
479-
DenseMatrixHandle elc_sponge_locations;
480-
if (elc_thickness.size()==elc_prototyp_map.size() && elc_x.size()==elc_prototyp_map.size() && elc_y.size()==elc_prototyp_map.size() && elc_z.size()==elc_prototyp_map.size() && elc_angle_rotation.size()==elc_prototyp_map.size())
577+
Variable::List new_table;
578+
DenseMatrixHandle elc_sponge_locations;
579+
auto tab_values = get(Parameters::TableValues).toVector();
580+
bool flip_normal=false;
581+
if (tab_values.size()==elc_prototyp_map.size() && elc_thickness.size()==elc_prototyp_map.size() && elc_x.size()==elc_prototyp_map.size() && elc_y.size()==elc_prototyp_map.size() && elc_z.size()==elc_prototyp_map.size() && elc_angle_rotation.size()==elc_prototyp_map.size())
481582
{
482583
VMesh* scalp_vmesh = scalp->vmesh();
483584
VField* scalp_vfld = scalp->vfield();
@@ -497,6 +598,22 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
497598
Vector norm;
498599
scalp_vmesh->synchronize(Mesh::NORMALS_E);
499600
scalp_vmesh->get_normal(norm,didx); /// ... get its normal
601+
//update GUI table normals
602+
double nx,ny,nz;
603+
Variable::List new_row;
604+
boost::tie(new_row,nx,ny,nz)=make_table_row(i,elc_x[i],elc_y[i],elc_z[i],norm.x(),norm.y(),norm.z());
605+
new_table.push_back(makeVariable("row" + boost::lexical_cast<std::string>(i), new_row));
606+
if (!(nx==0.0 && ny==0.0 && nz==0.0))
607+
{
608+
Vector norm2(nx,ny,nz);
609+
double dot_product=Dot(norm, norm2);
610+
norm = Vector(nx,ny,nz);
611+
if (dot_product<direction_bound)
612+
{
613+
flip_normal=true;
614+
}
615+
}
616+
500617
/// move coil prototype to projected location
501618
/// first, compute the transfer matrices
502619
std::vector<double> axis;
@@ -513,7 +630,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
513630
}
514631
FieldHandle prototype = elc_coil_proto[elc_prototyp_map[i]-1];
515632
FieldInformation fi(prototype);
516-
if(fi.is_trisurfmesh()) // put this to tms as well but for points, remark!
633+
if(fi.is_trisurfmesh())
517634
{
518635
GetMeshNodesAlgo algo_getfieldnodes;
519636
DenseMatrixHandle fieldnodes;
@@ -629,7 +746,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
629746
if (!tmp_sdf_vfld || tmp_sdf_vfld->num_values()<=0)
630747
{
631748
std::ostringstream ostr3;
632-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode. Make sure that prototype encapsulated scalp." << std::endl;
749+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode. Make sure that prototype encapsulated scalp." << std::endl;
633750
remark(ostr3.str());
634751
skip_current_iteration=true;
635752
continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
@@ -654,7 +771,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
654771
if(!found_elc_surf)
655772
{
656773
std::ostringstream ostr3;
657-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode (after sdf binarization). Make sure that prototype encapsulates scalp." << std::endl;
774+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (after sdf binarization). Make sure that prototype encapsulates scalp." << std::endl;
658775
remark(ostr3.str());
659776
skip_current_iteration=true;
660777
continue;/// in that case go to the next electrode -> leave the for loop thats iterating over
@@ -672,7 +789,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
672789
if (!final_electrode_sponge_surf_fld || final_electrode_sponge_surf_fld->num_values()<=0 || !final_electrode_sponge_surf_msh || final_electrode_sponge_surf_msh->num_elems()<=0)
673790
{
674791
std::ostringstream ostr3;
675-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode (conversion to constant data storage). Make sure that prototype encapsulates scalp." << std::endl;
792+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (conversion to constant data storage). Make sure that prototype encapsulates scalp." << std::endl;
676793
remark(ostr3.str());
677794
skip_current_iteration=true;
678795
continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
@@ -695,7 +812,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
695812
if (!found_elc_surf)
696813
{
697814
std::ostringstream ostr3;
698-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode (conversion to constant data storage). Make sure that prototype encapsulates scalp." << std::endl;
815+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (conversion to constant data storage). Make sure that prototype encapsulates scalp." << std::endl;
699816
remark(ostr3.str());
700817
skip_current_iteration=true;
701818
continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
@@ -726,7 +843,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
726843
if(!found_elc_surf)
727844
{
728845
std::ostringstream ostr3;
729-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode (after domainsplit). Make sure that prototype encapsulates scalp." << std::endl;
846+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (after domainsplit). Make sure that prototype encapsulates scalp." << std::endl;
730847
remark(ostr3.str());
731848
found_elc_surf=false;
732849
continue;/// in that case go to the next electrode -> leave the for loop thats iterating over i
@@ -775,7 +892,12 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
775892
x/=normal_mag;
776893
y/=normal_mag;
777894
z/=normal_mag;
778-
Point tmp_pt(q.x()-x*elc_thickness[i],q.y()-y*elc_thickness[i],q.z()-z*elc_thickness[i]);
895+
Point tmp_pt;
896+
if (!flip_normal)
897+
tmp_pt=Point(q.x()+x*elc_thickness[i],q.y()+y*elc_thickness[i],q.z()+z*elc_thickness[i]);
898+
else
899+
tmp_pt=Point(q.x()-x*elc_thickness[i],q.y()-y*elc_thickness[i],q.z()-z*elc_thickness[i]);
900+
779901
output_vmesh->add_point(tmp_pt);
780902
count_pts++;
781903
}
@@ -821,7 +943,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
821943
if (distance!=0)
822944
{
823945
std::ostringstream ostr3;
824-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode (could not find scalp bnd fragment node in scalp fragment). Make sure that prototype encapsulates scalp." << std::endl;
946+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (could not find scalp bnd fragment node in scalp fragment). Make sure that prototype encapsulates scalp." << std::endl;
825947
remark(ostr3.str());
826948
break;
827949
}
@@ -830,7 +952,7 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
830952
if (distance!=0)
831953
{
832954
std::ostringstream ostr3;
833-
ostr3 << " Electrode sponge/scalp surface could not be found for " << i << ". electrode (could not find scalp bnd fragment node in scalp fragment). Make sure that prototype encapsulates scalp." << std::endl;
955+
ostr3 << " Electrode sponge/scalp surface could not be found for " << i+1 << ". electrode (could not find scalp bnd fragment node in scalp fragment). Make sure that prototype encapsulates scalp." << std::endl;
834956
remark(ostr3.str());
835957
break;
836958
}
@@ -853,16 +975,23 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
853975
} else
854976
{
855977
std::ostringstream ostr3;
856-
ostr3 << " Trying to get boundary for scalp peace usind to create electrode " << i << ". Make sure that prototype encapsulates scalp." << std::endl;
978+
ostr3 << " Trying to get boundary for scalp peace usind to create electrode " << i+1 << ". Make sure that prototype encapsulates scalp." << std::endl;
857979
remark(ostr3.str());
858980
continue;
859981
}
860982

861983
}
862984
}
863985

864-
}
865-
986+
} else
987+
{
988+
std::ostringstream ostr3;
989+
ostr3 << " tDCS electrode definition for " << i+1 << ". row needs be a point cloud (with defined scalar or vectors data)." << std::endl;
990+
remark(ostr3.str());
991+
skip_current_iteration=true;
992+
continue;
993+
}
994+
866995
tdcs_vfld->resize_values();
867996
tdcs_vfld->set_values(field_values);
868997
output_vfld->resize_values();
@@ -891,7 +1020,9 @@ boost::tuple<DenseMatrixHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgo
8911020
remark(ostr3.str());
8921021
}
8931022

894-
return boost::make_tuple(elc_sponge_locations, electrode_field, output);
1023+
VariableHandle table2(new Variable(Name("Table"), new_table));
1024+
1025+
return boost::make_tuple(elc_sponge_locations, electrode_field, output, table2);
8951026
}
8961027

8971028
boost::tuple<VariableHandle, DenseMatrixHandle, FieldHandle, FieldHandle, FieldHandle> ElectrodeCoilSetupAlgorithm::run(const FieldHandle scalp, const DenseMatrixHandle locations, const std::vector<FieldHandle>& elc_coil_proto) const
@@ -1116,7 +1247,7 @@ boost::tuple<VariableHandle, DenseMatrixHandle, FieldHandle, FieldHandle, FieldH
11161247
if(c7==0 && c8==0 && c9==0)
11171248
{
11181249
std::ostringstream ostr3;
1119-
ostr3 << " The TMS coil defined in table row " << i << " could not get any valid normal information, found normal contained only zeros (0,0,0). " << std::endl;
1250+
ostr3 << " The TMS coil defined in table row " << i+1 << " could not get any valid normal information, found normal contained only zeros (0,0,0). " << std::endl;
11201251
remark(ostr3.str());
11211252
valid_normal=false;
11221253
}
@@ -1168,7 +1299,7 @@ boost::tuple<VariableHandle, DenseMatrixHandle, FieldHandle, FieldHandle, FieldH
11681299
} else
11691300
{
11701301
std::ostringstream ostr3;
1171-
ostr3 << " The TMS coil defined in table row " << i << " has no normal defined (NX,NY,NZ). Further, no normal could be taken from the linked prototyp field data. " << std::endl;
1302+
ostr3 << " The TMS coil defined in table row " << i+1 << " has no normal defined (NX,NY,NZ). Further, no normal could be taken from the linked prototyp field data. " << std::endl;
11721303
remark(ostr3.str());
11731304
}
11741305
}
@@ -1186,7 +1317,7 @@ boost::tuple<VariableHandle, DenseMatrixHandle, FieldHandle, FieldHandle, FieldH
11861317

11871318
if (t1==t2 && t1==t3 && t1==t4 && t1==t5 && t14>0 && t1>0)
11881319
{
1189-
boost::tie(elc_sponge_locations, electrodes_field, final_electrodes_field) = make_tdcs_electrodes(scalp, elc_coil_proto, elc_prototyp_map, elc_x, elc_y, elc_z, elc_angle_rotation, elc_thickness);
1320+
boost::tie(elc_sponge_locations, electrodes_field, final_electrodes_field, table_output) = make_tdcs_electrodes(scalp, elc_coil_proto, elc_prototyp_map, elc_x, elc_y, elc_z, elc_angle_rotation, elc_thickness, table_output);
11901321
valid_tdcs=true;
11911322
}
11921323

src/Core/Algorithms/BrainStimulator/ElectrodeCoilSetupAlgorithm.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ namespace BrainStimulator {
7878

7979
boost::tuple<VariableHandle, Datatypes::DenseMatrixHandle, FieldHandle, FieldHandle, FieldHandle> run(const FieldHandle scalp, const Datatypes::DenseMatrixHandle locations, const std::vector<FieldHandle>& elc_coil_proto) const;
8080
static const int number_of_columns = 10; /// number of GUI columns
81-
81+
static const double direction_bound;
8282
static const AlgorithmParameterName columnNames[number_of_columns];
8383

8484
private:
@@ -88,9 +88,11 @@ namespace BrainStimulator {
8888

8989
Datatypes::DenseMatrixHandle make_rotation_matrix_around_axis(double angle, std::vector<double>& axis_vector) const;
9090
Datatypes::DenseMatrixHandle make_rotation_matrix(const double angle, const std::vector<double>& normal) const;
91-
boost::tuple<Datatypes::DenseMatrixHandle, FieldHandle, FieldHandle> make_tdcs_electrodes(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto, const std::vector<double>& elc_prototyp_map, const std::vector<double>& elc_x, const std::vector<double>& elc_y, const std::vector<double>& elc_z, const std::vector<double>& elc_angle_rotation, const std::vector<double>& elc_thickness) const;
91+
boost::tuple<Datatypes::DenseMatrixHandle, FieldHandle, FieldHandle, VariableHandle> make_tdcs_electrodes(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto,
92+
const std::vector<double>& elc_prototyp_map, const std::vector<double>& elc_x, const std::vector<double>& elc_y, const std::vector<double>& elc_z, const std::vector<double>& elc_angle_rotation, const std::vector<double>& elc_thickness, VariableHandle table) const;
9293
FieldHandle make_tms(FieldHandle scalp, const std::vector<FieldHandle>& elc_coil_proto, const std::vector<double>& coil_prototyp_map, const std::vector<double>& coil_x, const std::vector<double>& coil_y, const std::vector<double>& coil_z, const std::vector<double>& coil_angle_rotation, const std::vector<double>& coil_nx, const std::vector<double>& coil_ny, const std::vector<double>& coil_nz) const;
9394
VariableHandle fill_table(FieldHandle scalp, Datatypes::DenseMatrixHandle locations, const std::vector<FieldHandle>& input) const;
95+
boost::tuple<Variable::List, double, double, double> make_table_row(int i,double x, double y, double z, double nx, double ny, double nz) const;
9496
};
9597

9698
}}}}

0 commit comments

Comments
 (0)