Changeset 57066a


Ignore:
Timestamp:
Sep 28, 2009, 8:00:33 PM (16 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
Children:
e4a379
Parents:
91e7e4a
git-author:
Frederik Heber <heber@…> (09/28/09 18:47:54)
git-committer:
Frederik Heber <heber@…> (09/28/09 20:00:33)
Message:

Various fixes and attempt to get convex hull working.

Moved tesselation writing to tesselation.cpp

  • WriteVrmlFile(), WriteRaster3dFile(), WriteTecplotFile() moved to tesselation.cpp
  • these also don't use molecule anymore, but the PointCloud structure (hence, bonds are no more visible)
  • new function TesselStruct::Output() which performs the writing
  • new function InsertSphereInRaster3D(), which places a sphere at the position of the last triangle
Location:
src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/boundary.cpp

    r91e7e4a r57066a  
    112112;
    113113
    114 /** Creates the objects in a VRML file.
    115  * \param *out output stream for debugging
    116  * \param *vrmlfile output stream for tecplot data
    117  * \param *Tess Tesselation structure with constructed triangles
    118  * \param *mol molecule structure with atom positions
    119  */
    120 void WriteVrmlFile(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, class molecule *mol)
    121 {
    122   atom *Walker = mol->start;
    123   bond *Binder = mol->first;
    124   int i;
    125   Vector *center = mol->DetermineCenterOfAll(out);
    126   if (vrmlfile != NULL) {
    127     //cout << Verbose(1) << "Writing Raster3D file ... ";
    128     *vrmlfile << "#VRML V2.0 utf8" << endl;
    129     *vrmlfile << "#Created by molecuilder" << endl;
    130     *vrmlfile << "#All atoms as spheres" << endl;
    131     while (Walker->next != mol->end) {
    132       Walker = Walker->next;
    133       *vrmlfile << "Sphere {" << endl << "  "; // 2 is sphere type
    134       for (i=0;i<NDIM;i++)
    135         *vrmlfile << Walker->x.x[i]-center->x[i] << " ";
    136       *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
    137     }
    138 
    139     *vrmlfile << "# All bonds as vertices" << endl;
    140     while (Binder->next != mol->last) {
    141       Binder = Binder->next;
    142       *vrmlfile << "3" << endl << "  "; // 2 is round-ended cylinder type
    143       for (i=0;i<NDIM;i++)
    144         *vrmlfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
    145       *vrmlfile << "\t0.03\t";
    146       for (i=0;i<NDIM;i++)
    147         *vrmlfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
    148       *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
    149     }
    150 
    151     *vrmlfile << "# All tesselation triangles" << endl;
    152     for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
    153       *vrmlfile << "1" << endl << "  "; // 1 is triangle type
    154       for (i=0;i<3;i++) { // print each node
    155         for (int j=0;j<NDIM;j++)  // and for each node all NDIM coordinates
    156           *vrmlfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
    157         *vrmlfile << "\t";
    158       }
    159       *vrmlfile << "1. 0. 0." << endl;  // red as colour
    160       *vrmlfile << "18" << endl << "  0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
    161     }
    162   } else {
    163     cerr << "ERROR: Given vrmlfile is " << vrmlfile << "." << endl;
    164   }
    165   delete(center);
    166 };
    167 
    168 /** Creates the objects in a raster3d file (renderable with a header.r3d).
    169  * \param *out output stream for debugging
    170  * \param *rasterfile output stream for tecplot data
    171  * \param *Tess Tesselation structure with constructed triangles
    172  * \param *mol molecule structure with atom positions
    173  */
    174 void WriteRaster3dFile(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, class molecule *mol)
    175 {
    176   atom *Walker = mol->start;
    177   bond *Binder = mol->first;
    178   int i;
    179   Vector *center = mol->DetermineCenterOfAll(out);
    180   if (rasterfile != NULL) {
    181     //cout << Verbose(1) << "Writing Raster3D file ... ";
    182     *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl;
    183     *rasterfile << "@header.r3d" << endl;
    184     *rasterfile << "# All atoms as spheres" << endl;
    185     while (Walker->next != mol->end) {
    186       Walker = Walker->next;
    187       *rasterfile << "2" << endl << "  ";  // 2 is sphere type
    188       for (i=0;i<NDIM;i++)
    189         *rasterfile << Walker->x.x[i]-center->x[i] << " ";
    190       *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
    191     }
    192 
    193     *rasterfile << "# All bonds as vertices" << endl;
    194     while (Binder->next != mol->last) {
    195       Binder = Binder->next;
    196       *rasterfile << "3" << endl << "  ";  // 2 is round-ended cylinder type
    197       for (i=0;i<NDIM;i++)
    198         *rasterfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
    199       *rasterfile << "\t0.03\t";
    200       for (i=0;i<NDIM;i++)
    201         *rasterfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
    202       *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
    203     }
    204 
    205     *rasterfile << "# All tesselation triangles" << endl;
    206     *rasterfile << "8\n  25. -1.   1. 1. 1.   0.0    0 0 0 2\n  SOLID     1.0 0.0 0.0\n  BACKFACE  0.3 0.3 1.0   0 0\n";
    207     for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
    208       *rasterfile << "1" << endl << "  ";  // 1 is triangle type
    209       for (i=0;i<3;i++) {  // print each node
    210         for (int j=0;j<NDIM;j++)  // and for each node all NDIM coordinates
    211           *rasterfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
    212         *rasterfile << "\t";
    213       }
    214       *rasterfile << "1. 0. 0." << endl;  // red as colour
    215       //*rasterfile << "18" << endl << "  0.5 0.5 0.5" << endl;  // 18 is transparency type for previous object
    216     }
    217     *rasterfile << "9\n#  terminating special property\n";
    218   } else {
    219     cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl;
    220   }
    221   delete(center);
    222 };
    223 
    224 /** This function creates the tecplot file, displaying the tesselation of the hull.
    225  * \param *out output stream for debugging
    226  * \param *tecplot output stream for tecplot data
    227  * \param N arbitrary number to differentiate various zones in the tecplot format
    228  */
    229 void WriteTecplotFile(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, class molecule *mol, int N)
    230 {
    231   if ((tecplot != NULL) && (TesselStruct != NULL)) {
    232     // write header
    233     *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
    234     *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\" \"U\"" << endl;
    235     *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" << TesselStruct->PointsOnBoundary.size() << ", E=" << TesselStruct->TrianglesOnBoundary.size() << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
    236     int *LookupList = new int[mol->AtomCount];
    237     for (int i = 0; i < mol->AtomCount; i++)
    238       LookupList[i] = -1;
    239 
    240     // print atom coordinates
    241     *out << Verbose(2) << "The following triangles were created:";
    242     int Counter = 1;
    243     TesselPoint *Walker = NULL;
    244     for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
    245       Walker = target->second->node;
    246       LookupList[Walker->nr] = Counter++;
    247       *tecplot << Walker->node->x[0] << " " << Walker->node->x[1] << " " << Walker->node->x[2] << " " << target->second->value << endl;
    248     }
    249     *tecplot << endl;
    250     // print connectivity
    251     for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
    252       *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
    253       *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
    254     }
    255     delete[] (LookupList);
    256     *out << endl;
    257   }
    258 }
    259 
    260114
    261115/** Determines the boundary points of a cluster.
     
    536390
    537391        // flip the line
    538         if (!mol->TesselStruct->PickFarthestofTwoBaselines(out, line))
     392        if (mol->TesselStruct->PickFarthestofTwoBaselines(out, line) == 0.)
    539393          *out << Verbose(1) << "ERROR: Correction of concave baselines failed!" << endl;
    540         else
     394        else {
     395          mol->TesselStruct->FlipBaseline(out, line);
    541396          *out << Verbose(1) << "INFO: Correction of concave baselines worked." << endl;
     397        }
    542398      }
    543399    }
     
    644500  class BoundaryLineSet *line = NULL;
    645501  bool Concavity;
     502  char dummy[MAXSTRINGSIZE];
    646503  PointMap::iterator PointRunner, PointAdvance;
    647504  LineMap::iterator LineRunner, LineAdvance;
     
    656513  }
    657514
    658   //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
    659   StoreTrianglesinFile(out, mol, filename, "-first");
    660 
    661515  // First step: RemovePointFromTesselatedSurface
     516  int run = 0;
     517  double tmp;
    662518  do {
    663519    Concavity = false;
     520    sprintf(dummy, "-first-%d", run);
     521    //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
     522    StoreTrianglesinFile(out, mol, filename, dummy);
     523
    664524    PointRunner = TesselStruct->PointsOnBoundary.begin();
    665525    PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
     
    671531        line = LineRunner->second;
    672532        *out << Verbose(2) << "INFO: Current line of point " << *point << " is " << *line << "." << endl;
    673       }
    674       if (!line->CheckConvexityCriterion(out)) {
    675         *out << Verbose(1) << "... point " << *point << " cannot be on convex envelope." << endl;
    676         // remove the point
    677         Concavity = true;
    678         TesselStruct->RemovePointFromTesselatedSurface(out, point);
     533        if (!line->CheckConvexityCriterion(out)) {
     534          // remove the point if needed
     535          *out << Verbose(1) << "... point " << *point << " cannot be on convex envelope." << endl;
     536          volume += TesselStruct->RemovePointFromTesselatedSurface(out, point);
     537          sprintf(dummy, "-first-%d", ++run);
     538          StoreTrianglesinFile(out, mol, filename, dummy);
     539          Concavity = true;
     540          break;
     541        }
    679542      }
    680543      PointRunner = PointAdvance;
    681544    }
    682545
     546    sprintf(dummy, "-second-%d", run);
    683547    //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
    684     //StoreTrianglesinFile(out, mol, filename, "-second");
     548    StoreTrianglesinFile(out, mol, filename, dummy);
    685549
    686550    // second step: PickFarthestofTwoBaselines
     
    693557      // take highest of both lines
    694558      if (TesselStruct->IsConvexRectangle(out, line) == NULL) {
    695         TesselStruct->PickFarthestofTwoBaselines(out, line);
    696         Concavity = true;
     559        tmp = TesselStruct->PickFarthestofTwoBaselines(out, line);
     560        volume += tmp;
     561        if (tmp != 0) {
     562          mol->TesselStruct->FlipBaseline(out, line);
     563          Concavity = true;
     564        }
    697565      }
    698566      LineRunner = LineAdvance;
    699567    }
     568    run++;
    700569  } while (Concavity);
    701   CalculateConcavityPerBoundaryPoint(out, TesselStruct);
    702   StoreTrianglesinFile(out, mol, filename, "-third");
     570  //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
     571  //StoreTrianglesinFile(out, mol, filename, "-third");
    703572
    704573  // third step: IsConvexRectangle
     
    717586      point = TesselStruct->IsConvexRectangle(out, line);
    718587      if (point != NULL)
    719         TesselStruct->RemovePointFromTesselatedSurface(out, point);
     588        volume += TesselStruct->RemovePointFromTesselatedSurface(out, point);
    720589    }
    721590    LineRunner = LineAdvance;
     
    723592
    724593  CalculateConcavityPerBoundaryPoint(out, TesselStruct);
    725   StoreTrianglesinFile(out, mol, filename, "-fourth");
     594  StoreTrianglesinFile(out, mol, filename, "");
    726595
    727596  // end
     597  *out << Verbose(1) << "Volume is " << volume << "." << endl;
    728598  *out << Verbose(0) << "End of ConvexizeNonconvexEnvelope" << endl;
    729599  return volume;
     
    993863    if ((*ListRunner)->TesselStruct == NULL) {
    994864      *out << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl;
    995       FindNonConvexBorder((ofstream *)&cout, (*ListRunner), LCList[i], NULL, 5.);
     865      FindNonConvexBorder((ofstream *)&cout, (*ListRunner), LCList[i], 5., NULL);
    996866    }
    997867    i++;
     
    1115985 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
    1116986 * \param *LCList atoms in LinkedCell list
     987 * \param RADIUS radius of the virtual sphere
    1117988 * \param *filename filename prefix for output of vertex data
    1118  * \para RADIUS radius of the virtual sphere
    1119  */
    1120 void FindNonConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename, const double RADIUS)
     989 */
     990void FindNonConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LCList, const double RADIUS, const char *filename = NULL)
    1121991{
    1122992  int N = 0;
    1123993  bool freeLC = false;
    1124   ofstream *tempstream = NULL;
    1125   char NumberName[255];
    1126   int TriangleFilesWritten = 0;
    1127994
    1128995  *out << Verbose(1) << "Entering search for non convex hull. " << endl;
     
    11411008  bool failflag = false;
    11421009
     1010  // initialise Linked Cell
    11431011  if (LCList == NULL) {
    11441012    LCList = new LinkedCell(mol, 2.*RADIUS);
     
    11461014  }
    11471015
     1016  // 1. get starting triangle
    11481017  mol->TesselStruct->FindStartingTriangle(out, RADIUS, LCList);
    11491018
     1019  // 2. expand from there
    11501020  baseline = mol->TesselStruct->LinesOnBoundary.begin();
    1151   // the outward most line is dangerous, as we may end up with wrapping up the starting triangle, hence
    1152   // terminating the algorithm too early.
    1153   if (baseline != mol->TesselStruct->LinesOnBoundary.end()) // skip first line as it its the outwardmost!
    1154         baseline++;
     1021  baseline++; // skip first line
    11551022  while ((baseline != mol->TesselStruct->LinesOnBoundary.end()) || (flag)) {
    11561023    if (baseline->second->triangles.size() == 1) {
    1157       failflag = mol->TesselStruct->FindNextSuitableTriangle(out, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, LCList); //the line is there, so there is a triangle, but only one.
     1024      // 3. find next triangle
     1025      failflag = mol->TesselStruct->FindNextSuitableTriangle(out, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, LCList); //the line is there, so there is a triangle, but only one.
    11581026      flag = flag || failflag;
    11591027      if (!failflag)
    11601028        cerr << "WARNING: FindNextSuitableTriangle failed." << endl;
     1029
    11611030      // write temporary envelope
    1162       if ((DoSingleStepOutput && (mol->TesselStruct->TrianglesOnBoundaryCount % SingleStepWidth == 0))) { // if we have a new triangle and want to output each new triangle configuration
    1163         TriangleMap::iterator runner = mol->TesselStruct->TrianglesOnBoundary.end();
    1164         runner--;
    1165         class BoundaryTriangleSet *triangle = runner->second;
    1166         if (triangle != NULL) {
    1167           sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
    1168           if (DoTecplotOutput) {
    1169             string NameofTempFile(filename);
    1170             NameofTempFile.append(NumberName);
    1171             for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
    1172             NameofTempFile.erase(npos, 1);
    1173             NameofTempFile.append(TecplotSuffix);
    1174             *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
    1175             tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
    1176             WriteTecplotFile(out, tempstream, mol->TesselStruct, mol, TriangleFilesWritten);
    1177             tempstream->close();
    1178             tempstream->flush();
    1179             delete(tempstream);
    1180           }
    1181 
    1182           if (DoRaster3DOutput) {
    1183             string NameofTempFile(filename);
    1184             NameofTempFile.append(NumberName);
    1185             for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
    1186             NameofTempFile.erase(npos, 1);
    1187             NameofTempFile.append(Raster3DSuffix);
    1188             *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
    1189             tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
    1190             WriteRaster3dFile(out, tempstream, mol->TesselStruct, mol);
    1191     //        // include the current position of the virtual sphere in the temporary raster3d file
    1192     //        // make the circumsphere's center absolute again
    1193     //        helper.CopyVector(BaseRay->endpoints[0]->node->node);
    1194     //        helper.AddVector(BaseRay->endpoints[1]->node->node);
    1195     //        helper.Scale(0.5);
    1196     //        (*it)->OptCenter.AddVector(&helper);
    1197     //        Vector *center = mol->DetermineCenterOfAll(out);
    1198     //        (*it)->OptCenter.SubtractVector(center);
    1199     //        delete(center);
    1200     //        // and add to file plus translucency object
    1201     //        *tempstream << "# current virtual sphere\n";
    1202     //        *tempstream << "8\n  25.0    0.6     -1.0 -1.0 -1.0     0.2        0 0 0 0\n";
    1203     //        *tempstream << "2\n  " << (*it)->OptCenter.x[0] << " "
    1204     //          << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
    1205     //          << "\t" << RADIUS << "\t1 0 0\n";
    1206     //        *tempstream << "9\n  terminating special property\n";
    1207             tempstream->close();
    1208             tempstream->flush();
    1209             delete(tempstream);
    1210           }
    1211         }
    1212         if (DoTecplotOutput || DoRaster3DOutput)
    1213           TriangleFilesWritten++;
     1031      if (filename != NULL) {
     1032        if ((DoSingleStepOutput && ((mol->TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0) || (mol->TesselStruct->TrianglesOnBoundary.size() > 8520 && mol->TesselStruct->TrianglesOnBoundary.size() <= 8530)))) { // if we have a new triangle and want to output each new triangle configuration
     1033          mol->TesselStruct->Output(out, filename, mol);
     1034        }
    12141035      }
     1036      baseline = mol->TesselStruct->LinesOnBoundary.end();
    12151037    } else {
    12161038      //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->triangles.size() << " triangles adjacent" << endl;
     
    12201042
    12211043    N++;
    1222     baseline++;
    12231044    if ((baseline == mol->TesselStruct->LinesOnBoundary.end()) && (flag)) {
    12241045      baseline = mol->TesselStruct->LinesOnBoundary.begin();   // restart if we reach end due to newly inserted lines
     1046      baseline++;
    12251047      flag = false;
    12261048    }
    12271049  }
     1050  // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
     1051  mol->TesselStruct->InsertStraddlingPoints(out, mol, LCList);
     1052//  mol->GoToFirst();
     1053//  class TesselPoint *Runner = NULL;
     1054//  while (!mol->IsEnd()) {
     1055//    Runner = mol->GetPoint();
     1056//    *out << Verbose(1) << "Checking on " << Runner->Name << " ... " << endl;
     1057//    if (!mol->TesselStruct->IsInnerPoint(out, Runner, LCList)) {
     1058//      *out << Verbose(2) << Runner->Name << " is outside of envelope, adding via degenerated triangles." << endl;
     1059//      mol->TesselStruct->AddBoundaryPointByDegeneratedTriangle(out, Runner, LCList);
     1060//    } else {
     1061//      *out << Verbose(2) << Runner->Name << " is inside of or on envelope." << endl;
     1062//    }
     1063//    mol->GoToNext();
     1064//  }
    12281065
    12291066  // Purges surplus triangles.
    12301067  mol->TesselStruct->RemoveDegeneratedTriangles();
    1231 
    1232   // write final envelope
    1233   if (filename != 0) {
    1234     *out << Verbose(1) << "Writing final tecplot file\n";
    1235     if (DoTecplotOutput) {
    1236       string OutputName(filename);
    1237       OutputName.append(TecplotSuffix);
    1238       ofstream *tecplot = new ofstream(OutputName.c_str());
    1239       WriteTecplotFile(out, tecplot, mol->TesselStruct, mol, -1);
    1240       tecplot->close();
    1241       delete(tecplot);
    1242     }
    1243     if (DoRaster3DOutput) {
    1244       string OutputName(filename);
    1245       OutputName.append(Raster3DSuffix);
    1246       ofstream *raster = new ofstream(OutputName.c_str());
    1247       WriteRaster3dFile(out, raster, mol->TesselStruct, mol);
    1248       raster->close();
    1249       delete(raster);
    1250     }
    1251   } else {
    1252     cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
    1253   }
    12541068
    12551069  cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
     
    12641078    *out << Verbose(2) << "None." << endl;
    12651079
    1266 //  // Tests the IsInnerAtom() function.
    1267 //  Vector x (0, 0, 0);
    1268 //  *out << Verbose(0) << "Point to check: " << x << endl;
    1269 //  *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, x, LCList)
    1270 //    << "for vector " << x << "." << endl;
    1271 //  TesselPoint* a = mol->TesselStruct->PointsOnBoundary.begin()->second->node;
    1272 //  *out << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;
    1273 //  *out << Verbose(0) << "Check: IsInnerAtom() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
    1274 //    << "for atom " << a << " (on boundary)." << endl;
    1275 //  LinkedNodes *List = NULL;
    1276 //  for (int i=0;i<NDIM;i++) { // each axis
    1277 //    LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell
    1278 //    for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)
    1279 //      for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {
    1280 //        List = LCList->GetCurrentCell();
    1281 //        //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
    1282 //        if (List != NULL) {
    1283 //          for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
    1284 //            if (mol->TesselStruct->PointsOnBoundary.find((*Runner)->nr) == mol->TesselStruct->PointsOnBoundary.end()) {
    1285 //              a = *Runner;
    1286 //              i=3;
    1287 //              for (int j=0;j<NDIM;j++)
    1288 //                LCList->n[j] = LCList->N[j];
    1289 //              break;
    1290 //            }
    1291 //          }
    1292 //        }
    1293 //      }
    1294 //  }
    1295 //  *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
    1296 //    << "for atom " << a << " (inside)." << endl;
     1080  // write final envelope
     1081  CalculateConcavityPerBoundaryPoint(out, mol->TesselStruct);
     1082  StoreTrianglesinFile(out, mol, filename, "");
    12971083
    12981084  if (freeLC)
     
    13001086  *out << Verbose(0) << "End of FindNonConvexBorder\n";
    13011087};
     1088
    13021089
    13031090/** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
  • src/boundary.hpp

    r91e7e4a r57066a  
    1616
    1717#define DEBUG 1
    18 #define DoSingleStepOutput 0
     18#define DoSingleStepOutput 1
    1919#define SingleStepWidth 1
    20 #define DoTecplotOutput 1
    21 #define DoRaster3DOutput 1
    22 #define DoVRMLOutput 1
    23 #define TecplotSuffix ".dat"
    24 #define Raster3DSuffix ".r3d"
    25 #define VRMLSUffix ".wrl"
    2620
    2721#define DistancePair pair < double, atom* >
     
    3832molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandAtomDisplacement, double RandMolDisplacement, bool DoRandomRotation);
    3933void FindConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename);
    40 void FindNonConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LC, const char *tempbasename, const double RADIUS);
     34void FindNonConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LC, const double RADIUS, const char *tempbasename);
    4135double ConvexizeNonconvexEnvelope(ofstream *out, class Tesselation *TesselStruct, molecule *mol, char *filename);
    4236void FindNextSuitablePoint(class BoundaryTriangleSet *BaseTriangle, class BoundaryLineSet *BaseLine, atom*& OptCandidate, Vector *OptCandidateCenter, double *ShortestAngle, const double RADIUS, LinkedCell *LC);
  • src/tesselation.cpp

    r91e7e4a r57066a  
    66 */
    77
     8#include "helpers.hpp"
     9#include "linkedcell.hpp"
    810#include "tesselation.hpp"
     11#include "tesselationhelpers.hpp"
     12#include "vector.hpp"
     13
     14class molecule;
    915
    1016// ======================================== Points on Boundary =================================
     
    3642BoundaryPointSet::~BoundaryPointSet()
    3743{
    38   cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
     44  //cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
    3945  if (!lines.empty())
    4046    cerr << "WARNING: Memory Leak! I " << *this << " am still connected to some lines." << endl;
     
    6672ostream & operator <<(ostream &ost, BoundaryPointSet &a)
    6773{
    68   ost << "[" << a.Nr << "|" << a.node->Name << "]";
     74  ost << "[" << a.Nr << "|" << a.node->Name << " at " << *a.node->node << "]";
    6975  return ost;
    7076}
     
    124130        for (LineMap::iterator Runner = erasor.first; Runner != erasor.second; Runner++)
    125131          if ((*Runner).second == this) {
    126             cout << Verbose(5) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
     132            //cout << Verbose(5) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
    127133            endpoints[i]->lines.erase(Runner);
    128134            break;
    129135          }
    130136      } else { // there's just a single line left
    131         if (endpoints[i]->lines.erase(Nr))
    132           cout << Verbose(5) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
     137        if (endpoints[i]->lines.erase(Nr)) {
     138          //cout << Verbose(5) << "Removing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
     139        }
    133140      }
    134141      if (endpoints[i]->lines.empty()) {
    135         cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
     142        //cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
    136143        if (endpoints[i] != NULL) {
    137144          delete(endpoints[i]);
     
    167174
    168175/** Checks whether the adjacent triangles of a baseline are convex or not.
    169  * We sum the two angles of each normal vector with a ficticious normnal vector from this baselinbe pointing outwards.
     176 * We sum the two angles of each height vector with respect to the center of the baseline.
    170177 * If greater/equal M_PI than we are convex.
    171178 * \param *out output stream for debugging
     
    177184  // get the two triangles
    178185  if (triangles.size() != 2) {
    179     *out << Verbose(1) << "ERROR: Baseline " << *this << " is connect to less than two triangles, Tesselation incomplete!" << endl;
     186    *out << Verbose(1) << "ERROR: Baseline " << *this << " is connected to less than two triangles, Tesselation incomplete!" << endl;
    180187    return true;
    181188  }
     
    200207    NormalCheck.Scale(sign);
    201208    sign = -sign;
    202     BaseLineNormal.SubtractVector(&runner->second->NormalVector);   // we subtract as BaseLineNormal has to point inward in direction of [pi,2pi]
     209    if (runner->second->NormalVector.NormSquared() > MYEPSILON)
     210      BaseLineNormal.CopyVector(&runner->second->NormalVector);   // yes, copy second on top of first
     211    else {
     212      *out << Verbose(1) << "CRITICAL: Triangle " << *runner->second << " has zero normal vector!" << endl;
     213      exit(255);
     214    }
    203215    node = runner->second->GetThirdEndpoint(this);
    204216    if (node != NULL) {
    205       //*out << Verbose(3) << "INFO: Third node for triangle " << *(runner->second) << " is " << *node << " at " << *(node->node->node) << "." << endl;
     217      *out << Verbose(3) << "INFO: Third node for triangle " << *(runner->second) << " is " << *node << " at " << *(node->node->node) << "." << endl;
    206218      helper[i].CopyVector(node->node->node);
    207219      helper[i].SubtractVector(&BaseLineCenter);
    208220      helper[i].MakeNormalVector(&BaseLine);  // we want to compare the triangle's heights' angles!
    209       //*out << Verbose(4) << "INFO: Height vector with respect to baseline is " << helper[i] << "." << endl;
     221      *out << Verbose(4) << "INFO: Height vector with respect to baseline is " << helper[i] << "." << endl;
    210222      i++;
    211223    } else {
    212       //*out << Verbose(2) << "WARNING: I cannot find third node in triangle, something's wrong." << endl;
     224      //*out << Verbose(2) << "ERROR: I cannot find third node in triangle, something's wrong." << endl;
    213225      return true;
    214226    }
    215227  }
    216   //*out << Verbose(3) << "INFO: BaselineNormal is " << BaseLineNormal << "." << endl;
     228  *out << Verbose(3) << "INFO: BaselineNormal is " << BaseLineNormal << "." << endl;
    217229  if (NormalCheck.NormSquared() < MYEPSILON) {
    218     *out << Verbose(2) << "ACCEPT: Normalvectors of both triangles are the same: convex." << endl;
     230    *out << Verbose(3) << "ACCEPT: Normalvectors of both triangles are the same: convex." << endl;
    219231    return true;
    220232  }
     233  BaseLineNormal.Scale(-1.);
    221234  double angle = GetAngle(helper[0], helper[1], BaseLineNormal);
    222235  if ((angle - M_PI) > -MYEPSILON) {
    223     *out << Verbose(2) << "ACCEPT: Angle is greater than pi: convex." << endl;
     236    *out << Verbose(3) << "ACCEPT: Angle is greater than pi: convex." << endl;
    224237    return true;
    225238  } else {
    226     *out << Verbose(2) << "REJECT: Angle is less than pi: concave." << endl;
     239    *out << Verbose(3) << "REJECT: Angle is less than pi: concave." << endl;
    227240    return false;
    228241  }
     
    261274ostream & operator <<(ostream &ost, BoundaryLineSet &a)
    262275{
    263   ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "]";
     276  ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << " at " << *a.endpoints[0]->node->node << "," << a.endpoints[1]->node->Name << " at " << *a.endpoints[1]->node->node << "]";
    264277  return ost;
    265278};
     
    331344  for (int i = 0; i < 3; i++) {
    332345    if (lines[i] != NULL) {
    333       if (lines[i]->triangles.erase(Nr))
    334         cout << Verbose(5) << "Triangle Nr." << Nr << " erased in line " << *lines[i] << "." << endl;
     346      if (lines[i]->triangles.erase(Nr)) {
     347        //cout << Verbose(5) << "Triangle Nr." << Nr << " erased in line " << *lines[i] << "." << endl;
     348      }
    335349      if (lines[i]->triangles.empty()) {
    336           cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
     350          //cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
    337351          delete (lines[i]);
    338352          lines[i] = NULL;
     
    340354    }
    341355  }
    342   cout << Verbose(5) << "Erasing triangle Nr." << Nr << " itself." << endl;
     356  //cout << Verbose(5) << "Erasing triangle Nr." << Nr << " itself." << endl;
    343357};
    344358
     
    450464};
    451465
     466/** Checks whether three given \a *Points coincide with triangle's endpoints.
     467 * \param *Points[3] pointer to BoundaryPointSet
     468 * \return true - is the very triangle, false - is not
     469 */
     470bool BoundaryTriangleSet::IsPresentTupel(class BoundaryTriangleSet *T)
     471{
     472  return (((endpoints[0] == T->endpoints[0])
     473            || (endpoints[0] == T->endpoints[1])
     474            || (endpoints[0] == T->endpoints[2])
     475          ) && (
     476            (endpoints[1] == T->endpoints[0])
     477            || (endpoints[1] == T->endpoints[1])
     478            || (endpoints[1] == T->endpoints[2])
     479          ) && (
     480            (endpoints[2] == T->endpoints[0])
     481            || (endpoints[2] == T->endpoints[1])
     482            || (endpoints[2] == T->endpoints[2])
     483
     484          ));
     485};
     486
    452487/** Returns the endpoint which is not contained in the given \a *line.
    453488 * \param *line baseline defining two endpoints
     
    484519ostream &operator <<(ostream &ost, BoundaryTriangleSet &a)
    485520{
    486   ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << ","
    487       << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
     521  ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << " at " << *a.endpoints[0]->node->node << ","
     522      << a.endpoints[1]->node->Name << " at " << *a.endpoints[1]->node->node << "," << a.endpoints[2]->node->Name << " at " << *a.endpoints[2]->node->node << "]";
    488523  return ost;
    489524};
     
    504539TesselPoint::~TesselPoint()
    505540{
    506   Free((void **)&Name, "TesselPoint::~TesselPoint: *Name");
    507541};
    508542
     
    511545ostream & operator << (ostream &ost, const TesselPoint &a)
    512546{
    513   ost << "[" << (a.Name) << "|" << &a << "]";
     547  ost << "[" << (a.Name) << "|" << a.Name << " at " << *a.node << "]";
    514548  return ost;
    515549};
     
    568602  TrianglesOnBoundaryCount = 0;
    569603  InternalPointer = PointsOnBoundary.begin();
     604  LastTriangle = NULL;
     605  TriangleFilesWritten = 0;
    570606}
    571607;
     
    584620      cerr << "ERROR: The triangle " << runner->first << " has already been free'd." << endl;
    585621  }
     622  cout << "This envelope was written to file " << TriangleFilesWritten << " times(s)." << endl;
    586623}
    587624;
     
    12321269void Tesselation::AlwaysAddTesselationTriangleLine(class BoundaryPointSet *a, class BoundaryPointSet *b, int n)
    12331270{
    1234   cout << Verbose(4) << "Adding line between " << *(a->node) << " and " << *(b->node) << "." << endl;
     1271  cout << Verbose(4) << "Adding line [" << LinesOnBoundaryCount << "|" << *(a->node) << " and " << *(b->node) << "." << endl;
    12351272  BPS[0] = a;
    12361273  BPS[1] = b;
     
    12521289  TrianglesOnBoundary.insert(TrianglePair(TrianglesOnBoundaryCount, BTS));
    12531290  TrianglesOnBoundaryCount++;
     1291
     1292  // set as last new triangle
     1293  LastTriangle = BTS;
    12541294
    12551295  // NOTE: add triangle to local maps is done in constructor of BoundaryTriangleSet
     
    15241564  CandidateList *OptCandidates = new CandidateList();
    15251565  for (int k=0;k<NDIM;k++) {
     1566    Oben.Zero();
    15261567    Oben.x[k] = 1.;
    15271568    FirstPoint = MaxPoint[k];
     
    15321573    ShortestAngle = 999999.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant.
    15331574
    1534     FindSecondPointForTesselation(FirstPoint, NULL, Oben, OptCandidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
     1575    FindSecondPointForTesselation(FirstPoint, Oben, OptCandidate, &ShortestAngle, RADIUS, LC); // we give same point as next candidate as its bonds are looked into in find_second_...
    15351576    SecondPoint = OptCandidate;
    15361577    if (SecondPoint == NULL)  // have we found a second point?
    15371578      continue;
    1538     else
    1539       cout << Verbose(1) << "Found second point is at " << *SecondPoint->node << ".\n";
    15401579
    15411580    helper.CopyVector(FirstPoint->node);
     
    15591598
    15601599    // adding point 1 and point 2 and add the line between them
     1600    cout << Verbose(1) << "Coordinates of start node at " << *FirstPoint->node << "." << endl;
    15611601    AddTesselationPoint(FirstPoint, 0);
     1602    cout << Verbose(1) << "Found second point is at " << *SecondPoint->node << ".\n";
    15621603    AddTesselationPoint(SecondPoint, 1);
    15631604    AddTesselationLine(TPS[0], TPS[1], 0);
     
    16321673 * @param *LC LinkedCell structure with neighbouring points
    16331674 */
    1634 bool Tesselation::FindNextSuitableTriangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, int N, LinkedCell *LC)
     1675bool Tesselation::FindNextSuitableTriangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, LinkedCell *LC)
    16351676{
    16361677  cout << Verbose(0) << "Begin of FindNextSuitableTriangle\n";
     
    16671708    CircleRadius = RADIUS*RADIUS - radius/4.;
    16681709    CirclePlaneNormal.Normalize();
    1669     cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
     1710    //cout << Verbose(2) << "INFO: CircleCenter is at " << CircleCenter << ", CirclePlaneNormal is " << CirclePlaneNormal << " with circle radius " << sqrt(CircleRadius) << "." << endl;
    16701711
    16711712    // construct old center
     
    17541795        result = false;
    17551796      }
    1756     } else if (existentTrianglesCount == 1) { // If there is a planar region within the structure, we need this triangle a second time.
     1797    } else if ((existentTrianglesCount >= 1) && (existentTrianglesCount <= 3)) { // If there is a planar region within the structure, we need this triangle a second time.
    17571798        AddTesselationPoint((*it)->point, 0);
    17581799        AddTesselationPoint(BaseRay->endpoints[0]->node, 1);
     
    17951836    // set baseline to new ray from ref point (here endpoints[0]->node) to current candidate (here (*it)->point))
    17961837    BaseRay = BLS[0];
     1838    if ((BTS != NULL) && (BTS->NormalVector.NormSquared() < MYEPSILON)) {
     1839      *out << Verbose(1) << "CRITICAL: Triangle " << *BTS << " has zero normal vector!" << endl;
     1840      exit(255);
     1841    }
     1842
    17971843  }
    17981844
     
    18131859 * \param *out output stream for debugging
    18141860 * \param *Base line to be flipped
    1815  * \return NULL - concave, otherwise endpoint that makes it concave
     1861 * \return NULL - convex, otherwise endpoint that makes it concave
    18161862 */
    18171863class BoundaryPointSet *Tesselation::IsConvexRectangle(ofstream *out, class BoundaryLineSet *Base)
     
    18901936 * \param *out output stream for debugging
    18911937 * \param *Base line to be flipped
    1892  * \return true - line was changed, false - same line as before
    1893  */
    1894 bool Tesselation::PickFarthestofTwoBaselines(ofstream *out, class BoundaryLineSet *Base)
     1938 * \return volume change due to flipping (0 - then no flipped occured)
     1939 */
     1940double Tesselation::PickFarthestofTwoBaselines(ofstream *out, class BoundaryLineSet *Base)
    18951941{
    18961942  class BoundaryLineSet *OtherBase;
    18971943  Vector *ClosestPoint[2];
     1944  double volume;
    18981945
    18991946  int m=0;
     
    19151962  Distance.CopyVector(ClosestPoint[1]);
    19161963  Distance.SubtractVector(ClosestPoint[0]);
     1964
     1965  // calculate volume
     1966  volume = CalculateVolumeofGeneralTetraeder(Base->endpoints[1]->node->node, OtherBase->endpoints[0]->node->node, OtherBase->endpoints[1]->node->node, Base->endpoints[0]->node->node);
    19171967
    19181968  // delete the temporary other base line and the closest points
     
    19291979    if (Base->triangles.size() < 2) {
    19301980      *out << Verbose(2) << "ERROR: Less than two triangles are attached to this baseline!" << endl;
    1931       return false;
     1981      return 0.;
    19321982    }
    19331983    for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
     
    19391989    if (Distance.ScalarProduct(&BaseLineNormal) > MYEPSILON) { // Distance points outwards, hence OtherBase higher than Base -> flip
    19401990      *out << Verbose(2) << "ACCEPT: Other base line would be higher: Flipping baseline." << endl;
    1941       FlipBaseline(out, Base);
    1942       return true;
     1991      // calculate volume summand as a general tetraeder
     1992      return volume;
    19431993    } else {  // Base higher than OtherBase -> do nothing
    19441994      *out << Verbose(2) << "REJECT: Base line is higher: Nothing to do." << endl;
    1945       return false;
    1946     }
    1947   }
    1948 };
    1949 
    1950 /** Returns the closest point on \a *Base with respect to \a *OtherBase.
    1951  * \param *out output stream for debugging
    1952  * \param *Base reference line
    1953  * \param *OtherBase other base line
    1954  * \return Vector on reference line that has closest distance
    1955  */
    1956 Vector * GetClosestPointBetweenLine(ofstream *out, class BoundaryLineSet *Base, class BoundaryLineSet *OtherBase)
    1957 {
    1958   // construct the plane of the two baselines (i.e. take both their directional vectors)
    1959   Vector Normal;
    1960   Vector Baseline, OtherBaseline;
    1961   Baseline.CopyVector(Base->endpoints[1]->node->node);
    1962   Baseline.SubtractVector(Base->endpoints[0]->node->node);
    1963   OtherBaseline.CopyVector(OtherBase->endpoints[1]->node->node);
    1964   OtherBaseline.SubtractVector(OtherBase->endpoints[0]->node->node);
    1965   Normal.CopyVector(&Baseline);
    1966   Normal.VectorProduct(&OtherBaseline);
    1967   Normal.Normalize();
    1968   *out << Verbose(4) << "First direction is " << Baseline << ", second direction is " << OtherBaseline << ", normal of intersection plane is " << Normal << "." << endl;
    1969 
    1970   // project one offset point of OtherBase onto this plane (and add plane offset vector)
    1971   Vector NewOffset;
    1972   NewOffset.CopyVector(OtherBase->endpoints[0]->node->node);
    1973   NewOffset.SubtractVector(Base->endpoints[0]->node->node);
    1974   NewOffset.ProjectOntoPlane(&Normal);
    1975   NewOffset.AddVector(Base->endpoints[0]->node->node);
    1976   Vector NewDirection;
    1977   NewDirection.CopyVector(&NewOffset);
    1978   NewDirection.AddVector(&OtherBaseline);
    1979 
    1980   // calculate the intersection between this projected baseline and Base
    1981   Vector *Intersection = new Vector;
    1982   Intersection->GetIntersectionOfTwoLinesOnPlane(out, Base->endpoints[0]->node->node, Base->endpoints[1]->node->node, &NewOffset, &NewDirection, &Normal);
    1983   Normal.CopyVector(Intersection);
    1984   Normal.SubtractVector(Base->endpoints[0]->node->node);
    1985   *out << Verbose(3) << "Found closest point on " << *Base << " at " << *Intersection << ", factor in line is " << fabs(Normal.ScalarProduct(&Baseline)/Baseline.NormSquared()) << "." << endl;
    1986 
    1987   return Intersection;
     1995      return 0.;
     1996    }
     1997  }
    19881998};
    19891999
     
    19932003 * \param *out output stream for debugging
    19942004 * \param *Base line to be flipped
    1995  * \return true - flipping successful, false - something went awry
    1996  */
    1997 bool Tesselation::FlipBaseline(ofstream *out, class BoundaryLineSet *Base)
     2005 * \return pointer to allocated new baseline - flipping successful, NULL - something went awry
     2006 */
     2007class BoundaryLineSet * Tesselation::FlipBaseline(ofstream *out, class BoundaryLineSet *Base)
    19982008{
    19992009  class BoundaryLineSet *OldLines[4], *NewLine;
     
    20092019  if (Base->triangles.size() < 2) {
    20102020    *out << Verbose(2) << "ERROR: Less than two triangles are attached to this baseline!" << endl;
    2011     return false;
     2021    return NULL;
    20122022  }
    20132023  for (TriangleMap::iterator runner = Base->triangles.begin(); runner != Base->triangles.end(); runner++) {
     
    20452055  if (i<4) {
    20462056    *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
    2047     return false;
     2057    return NULL;
    20482058  }
    20492059  for (int j=0;j<4;j++)
    20502060    if (OldLines[j] == NULL) {
    20512061      *out << Verbose(1) << "ERROR: We have not gathered enough baselines!" << endl;
    2052       return false;
     2062      return NULL;
    20532063    }
    20542064  for (int j=0;j<2;j++)
    20552065    if (OldPoints[j] == NULL) {
    20562066      *out << Verbose(1) << "ERROR: We have not gathered enough endpoints!" << endl;
    2057       return false;
     2067      return NULL;
    20582068    }
    20592069
     
    20992109  } else {
    21002110    *out << Verbose(1) << "The four old lines do not connect, something's utterly wrong here!" << endl;
    2101     return false;
     2111    return NULL;
    21022112  }
    21032113
    21042114  *out << Verbose(1) << "End of FlipBaseline" << endl;
    2105   return true;
     2115  return NewLine;
    21062116};
    21072117
     
    21092119/** Finds the second point of starting triangle.
    21102120 * \param *a first node
    2111  * \param *Candidate pointer to candidate node on return
    21122121 * \param Oben vector indicating the outside
    21132122 * \param OptCandidate reference to recommended candidate on return
     
    21162125 * \param *LC LinkedCell structure with neighbouring points
    21172126 */
    2118 void Tesselation::FindSecondPointForTesselation(TesselPoint* a, TesselPoint* Candidate, Vector Oben, TesselPoint*& OptCandidate, double Storage[3], double RADIUS, LinkedCell *LC)
     2127void Tesselation::FindSecondPointForTesselation(TesselPoint* a, Vector Oben, TesselPoint*& OptCandidate, double Storage[3], double RADIUS, LinkedCell *LC)
    21192128{
    21202129  cout << Verbose(2) << "Begin of FindSecondPointForTesselation" << endl;
    21212130  Vector AngleCheck;
     2131  class TesselPoint* Candidate = NULL;
    21222132  double norm = -1., angle;
    21232133  LinkedNodes *List = NULL;
     
    22542264  cout << Verbose(1) << "Begin of FindThirdPointForTesselation" << endl;
    22552265
    2256   //cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
     2266  cout << Verbose(2) << "INFO: NormalVector of BaseTriangle is " << NormalVector << "." << endl;
    22572267
    22582268  // construct center of circle
     
    22792289    radius = OldSphereCenter.ScalarProduct(&OldSphereCenter);
    22802290    if (fabs(radius - CircleRadius) < HULLEPSILON) {
     2291      //cout << Verbose(2) << "INFO: OldSphereCenter is at " << OldSphereCenter << "." << endl;
    22812292
    22822293      // check SearchDirection
     
    24552466  TesselPoint *trianglePoints[3];
    24562467  TesselPoint *SecondPoint = NULL;
     2468  list<BoundaryTriangleSet*> *triangles = NULL;
    24572469
    24582470  if (LinesOnBoundary.empty()) {
     
    24652477  // check whether closest point is "too close" :), then it's inside
    24662478  if (trianglePoints[0] == NULL) {
    2467     *out << Verbose(1) << "Is the only point, no one else is closeby." << endl;
     2479    *out << Verbose(2) << "Is the only point, no one else is closeby." << endl;
    24682480    return NULL;
    24692481  }
    24702482  if (trianglePoints[0]->node->DistanceSquared(x) < MYEPSILON) {
    2471     *out << Verbose(1) << "Point is right on a tesselation point, no nearest triangle." << endl;
    2472     return NULL;
    2473   }
    2474   list<TesselPoint*> *connectedClosestPoints = GetCircleOfConnectedPoints(out, trianglePoints[0], x);
    2475   trianglePoints[1] = connectedClosestPoints->front();
    2476   trianglePoints[2] = connectedClosestPoints->back();
    2477   for (int i=0;i<3;i++) {
    2478     if (trianglePoints[i] == NULL) {
    2479       *out << Verbose(1) << "IsInnerPoint encounters serious error, point " << i << " not found." << endl;
    2480     }
    2481     //*out << Verbose(1) << "List of possible points:" << endl;
    2482     //*out << Verbose(2) << *trianglePoints[i] << endl;
    2483   }
    2484 
    2485   list<BoundaryTriangleSet*> *triangles = FindTriangles(trianglePoints);
    2486 
    2487   delete(connectedClosestPoints);
     2483    *out << Verbose(2) << "Point is right on a tesselation point, no nearest triangle." << endl;
     2484    PointMap::iterator PointRunner = PointsOnBoundary.find(trianglePoints[0]->nr);
     2485    triangles = new list<BoundaryTriangleSet*>;
     2486    if (PointRunner != PointsOnBoundary.end()) {
     2487      for(LineMap::iterator LineRunner = PointRunner->second->lines.begin(); LineRunner != PointRunner->second->lines.end(); LineRunner++)
     2488        for(TriangleMap::iterator TriangleRunner = LineRunner->second->triangles.begin(); TriangleRunner != LineRunner->second->triangles.end(); TriangleRunner++)
     2489          triangles->push_back(TriangleRunner->second);
     2490      triangles->sort();
     2491      triangles->unique();
     2492    } else {
     2493      PointRunner = PointsOnBoundary.find(SecondPoint->nr);
     2494      trianglePoints[0] = SecondPoint;
     2495      if (PointRunner != PointsOnBoundary.end()) {
     2496        for(LineMap::iterator LineRunner = PointRunner->second->lines.begin(); LineRunner != PointRunner->second->lines.end(); LineRunner++)
     2497          for(TriangleMap::iterator TriangleRunner = LineRunner->second->triangles.begin(); TriangleRunner != LineRunner->second->triangles.end(); TriangleRunner++)
     2498            triangles->push_back(TriangleRunner->second);
     2499        triangles->sort();
     2500        triangles->unique();
     2501      } else {
     2502        *out << Verbose(1) << "ERROR: I cannot find a boundary point to the tessel point " << *trianglePoints[0] << "." << endl;
     2503        return NULL;
     2504      }
     2505    }
     2506  } else {
     2507    list<TesselPoint*> *connectedClosestPoints = GetCircleOfConnectedPoints(out, trianglePoints[0], x);
     2508    trianglePoints[1] = connectedClosestPoints->front();
     2509    trianglePoints[2] = connectedClosestPoints->back();
     2510    for (int i=0;i<3;i++) {
     2511      if (trianglePoints[i] == NULL) {
     2512        *out << Verbose(1) << "ERROR: IsInnerPoint encounters serious error, point " << i << " not found." << endl;
     2513      }
     2514      *out << Verbose(1) << "List of triangle points:" << endl;
     2515      *out << Verbose(2) << *trianglePoints[i] << endl;
     2516    }
     2517
     2518    triangles = FindTriangles(trianglePoints);
     2519    *out << Verbose(1) << "List of possible triangles:" << endl;
     2520    for(list<BoundaryTriangleSet*>::iterator Runner = triangles->begin(); Runner != triangles->end(); Runner++)
     2521      *out << Verbose(2) << **Runner << endl;
     2522
     2523    delete(connectedClosestPoints);
     2524  }
    24882525 
    24892526  if (triangles->empty()) {
    2490     *out << Verbose(0) << "Error: There is no nearest triangle. Please check the tesselation structure.";
     2527    *out << Verbose(0) << "ERROR: There is no nearest triangle. Please check the tesselation structure.";
     2528    delete(triangles);
    24912529    return NULL;
    24922530  } else
     
    25042542  class BoundaryTriangleSet *result = NULL;
    25052543  list<BoundaryTriangleSet*> *triangles = FindClosestTrianglesToPoint(out, x, LC);
     2544  Vector Center;
    25062545
    25072546  if (triangles == NULL)
    25082547    return NULL;
    25092548
    2510   if (x->ScalarProduct(&triangles->front()->NormalVector) < 0)
    2511     result = triangles->back();
    2512   else
     2549  if (triangles->size() == 1) { // there is no degenerate case
    25132550    result = triangles->front();
    2514 
     2551    *out << Verbose(2) << "Normal Vector of this triangle is " << result->NormalVector << "." << endl;
     2552  } else {
     2553    result = triangles->front();
     2554    result->GetCenter(&Center);
     2555    Center.SubtractVector(x);
     2556    *out << Verbose(2) << "Normal Vector of this front side is " << result->NormalVector << "." << endl;
     2557    if (Center.ScalarProduct(&result->NormalVector) < 0) {
     2558      result = triangles->back();
     2559      *out << Verbose(2) << "Normal Vector of this back side is " << result->NormalVector << "." << endl;
     2560      if (Center.ScalarProduct(&result->NormalVector) < 0) {
     2561        *out << Verbose(1) << "ERROR: Front and back side yield NormalVector in wrong direction!" << endl;
     2562      }
     2563    }
     2564  }
    25152565  delete(triangles);
    25162566  return result;
     
    25272577{
    25282578  class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, &Point, LC);
    2529   if (result == NULL)
     2579  Vector Center;
     2580
     2581  if (result == NULL) {// is boundary point or only point in point cloud?
     2582    *out << Verbose(1) << Point << " is the only point in vicinity." << endl;
     2583    return false;
     2584  }
     2585
     2586  result->GetCenter(&Center);
     2587  *out << Verbose(3) << "INFO: Central point of the triangle is " << Center << "." << endl;
     2588  Center.SubtractVector(&Point);
     2589  *out << Verbose(3) << "INFO: Vector from center to point to test is " << Center << "." << endl;
     2590  if (Center.ScalarProduct(&result->NormalVector) > -MYEPSILON) {
     2591    *out << Verbose(1) << Point << " is an inner point." << endl;
    25302592    return true;
    2531   if (Point.ScalarProduct(&result->NormalVector) < 0)
    2532     return true;
    2533   else
     2593  } else {
     2594    *out << Verbose(1) << Point << " is NOT an inner point." << endl;
    25342595    return false;
     2596  }
    25352597}
    25362598
     
    25442606bool Tesselation::IsInnerPoint(ofstream *out, TesselPoint *Point, LinkedCell* LC)
    25452607{
    2546   class BoundaryTriangleSet *result = FindClosestTriangleToPoint(out, Point->node, LC);
    2547   if (result == NULL)
    2548     return true;
    2549   if (Point->node->ScalarProduct(&result->NormalVector) < 0)
    2550     return true;
    2551   else
    2552     return false;
     2608  return IsInnerPoint(out, *(Point->node), LC);
    25532609}
    25542610
     
    27052761  }
    27062762
    2707   map <class BoundaryLineSet *, bool> Touched;
    2708   map <class BoundaryLineSet *, bool>::iterator line;
    2709   for (LineMap::iterator runner = ReferencePoint->lines.begin(); runner != ReferencePoint->lines.end(); runner++)
    2710     Touched.insert( pair <class BoundaryLineSet *, bool>(runner->second, false) );
     2763  map <class BoundaryLineSet *, bool> TouchedLine;
     2764  map <class BoundaryTriangleSet *, bool> TouchedTriangle;
     2765  map <class BoundaryLineSet *, bool>::iterator LineRunner;
     2766  map <class BoundaryTriangleSet *, bool>::iterator TriangleRunner;
     2767  for (LineMap::iterator Runner = ReferencePoint->lines.begin(); Runner != ReferencePoint->lines.end(); Runner++) {
     2768    TouchedLine.insert( pair <class BoundaryLineSet *, bool>(Runner->second, false) );
     2769    for (TriangleMap::iterator Sprinter = Runner->second->triangles.begin(); Sprinter != Runner->second->triangles.end(); Sprinter++)
     2770      TouchedTriangle.insert( pair <class BoundaryTriangleSet *, bool>(Sprinter->second, false) );
     2771  }
    27112772  if (!ReferencePoint->lines.empty()) {
    27122773    for (LineMap::iterator runner = ReferencePoint->lines.begin(); runner != ReferencePoint->lines.end(); runner++) {
    2713       line = Touched.find(runner->second);
    2714       if (line == Touched.end()) {
     2774      LineRunner = TouchedLine.find(runner->second);
     2775      if (LineRunner == TouchedLine.end()) {
    27152776        *out << Verbose(2) << "ERROR: I could not find " << *runner->second << " in the touched list." << endl;
    2716       } else if (!line->second) {
    2717         line->second = true;
     2777      } else if (!LineRunner->second) {
     2778        LineRunner->second = true;
    27182779        connectedPath = new list<TesselPoint*>;
    27192780        triangle = NULL;
     
    27282789
    27292790          // find next triangle
    2730           for (TriangleMap::iterator TriangleRunner = CurrentLine->triangles.begin(); TriangleRunner != CurrentLine->triangles.end(); TriangleRunner++) {
    2731             if (TriangleRunner->second != triangle) { // look for first triangle not equal to old one
    2732               triangle = TriangleRunner->second;
    2733               break;
     2791          for (TriangleMap::iterator Runner = CurrentLine->triangles.begin(); Runner != CurrentLine->triangles.end(); Runner++) {
     2792            *out << Verbose(3) << "INFO: Inspecting triangle " << *Runner->second << "." << endl;
     2793            if ((Runner->second != triangle)) { // look for first triangle not equal to old one
     2794              triangle = Runner->second;
     2795              TriangleRunner = TouchedTriangle.find(triangle);
     2796              if (TriangleRunner != TouchedTriangle.end()) {
     2797                if (!TriangleRunner->second) {
     2798                  TriangleRunner->second = true;
     2799                  *out << Verbose(3) << "INFO: Connecting triangle is " << *triangle << "." << endl;
     2800                  break;
     2801                } else {
     2802                  *out << Verbose(3) << "INFO: Skipping " << *triangle << ", as we have already visited it." << endl;
     2803                  triangle = NULL;
     2804                }
     2805              } else {
     2806                *out << Verbose(2) << "ERROR: I could not find " << *triangle << " in the touched list." << endl;
     2807                triangle = NULL;
     2808              }
    27342809            }
    27352810          }
     2811          if (triangle == NULL)
     2812            break;
    27362813          // find next line
    27372814          for (int i=0;i<3;i++) {
    27382815            if ((triangle->lines[i] != CurrentLine) && (triangle->lines[i]->ContainsBoundaryPoint(ReferencePoint))) { // not the current line and still containing Point
    27392816              CurrentLine = triangle->lines[i];
    2740 
     2817              *out << Verbose(3) << "INFO: Connecting line is " << *CurrentLine << "." << endl;
    27412818              break;
    27422819            }
    27432820          }
    2744           line = Touched.find(CurrentLine);
    2745           if (line == Touched.end())
     2821          LineRunner = TouchedLine.find(CurrentLine);
     2822          if (LineRunner == TouchedLine.end())
    27462823            *out << Verbose(2) << "ERROR: I could not find " << *CurrentLine << " in the touched list." << endl;
    27472824          else
    2748             line->second = true;
     2825            LineRunner->second = true;
    27492826          // find next point
    27502827          CurrentPoint = CurrentLine->GetOtherEndpoint(ReferencePoint);
     
    27532830        // last point is missing, as it's on start line
    27542831        *out << Verbose(3) << "INFO: Putting " << *CurrentPoint << " at end of path." << endl;
    2755         connectedPath->push_back(StartLine->GetOtherEndpoint(ReferencePoint)->node);
     2832        if (StartLine->GetOtherEndpoint(ReferencePoint)->node != connectedPath->back())
     2833          connectedPath->push_back(StartLine->GetOtherEndpoint(ReferencePoint)->node);
    27562834
    27572835        ListOfPaths->push_back(connectedPath);
     
    28532931
    28542932/** Removes a boundary point from the envelope while keeping it closed.
    2855  * We create new triangles and remove the old ones connected to the point.
     2933 * We remove the old triangles connected to the point and re-create new triangles to close the surface following this ansatz:
     2934 *  -# a closed path(s) of boundary points surrounding the point to be removed is constructed
     2935 *  -# on each closed path, we pick three adjacent points, create a triangle with them and subtract the middle point from the path
     2936 *  -# we advance two points (i.e. the next triangle will start at the ending point of the last triangle) and continue as before
     2937 *  -# the surface is closed, when the path is empty
     2938 * Thereby, we (hopefully) make sure that the removed points remains beneath the surface (this is checked via IsInnerPoint eventually).
    28562939 * \param *out output stream for debugging
    28572940 * \param *point point to be removed
     
    28612944  class BoundaryLineSet *line = NULL;
    28622945  class BoundaryTriangleSet *triangle = NULL;
    2863   Vector OldPoint, TetraederVector[3];
     2946  Vector OldPoint, NormalVector;
    28642947  double volume = 0;
    28652948  int count = 0;
     
    28872970    count+=LineRunner->second->triangles.size();
    28882971  map<class BoundaryTriangleSet *, int> Candidates;
    2889   for (LineMap::iterator LineRunner = point->lines.begin(); (point != NULL) && (LineRunner != point->lines.end()); LineRunner++) {
     2972  for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
    28902973    line = LineRunner->second;
    28912974    for (TriangleMap::iterator TriangleRunner = line->triangles.begin(); TriangleRunner != line->triangles.end(); TriangleRunner++) {
     
    28972980  // remove all triangles
    28982981  count=0;
     2982  NormalVector.Zero();
    28992983  for (map<class BoundaryTriangleSet *, int>::iterator Runner = Candidates.begin(); Runner != Candidates.end(); Runner++) {
    29002984    *out << Verbose(3) << "INFO: Removing triangle " << *(Runner->first) << "." << endl;
     2985    NormalVector.SubtractVector(&Runner->first->NormalVector); // has to point inward
    29012986    RemoveTesselationTriangle(Runner->first);
    29022987    count++;
     
    29072992  list<list<TesselPoint*> *>::iterator ListRunner = ListAdvance;
    29082993  map<class BoundaryTriangleSet *, int>::iterator NumberRunner = Candidates.begin();
     2994  list<TesselPoint*>::iterator StartNode, MiddleNode, EndNode;
     2995  double angle;
     2996  double smallestangle;
     2997  Vector Point, Reference, OrthogonalVector;
    29092998  if (count > 2) {  // less than three triangles, then nothing will be created
    29102999    class TesselPoint *TriangleCandidates[3];
     
    29153004
    29163005      connectedPath = *ListRunner;
    2917       // initialize the path to start
    2918       list<TesselPoint*>::iterator CircleRunner = connectedPath->begin();
    2919       list<TesselPoint*>::iterator OtherCircleRunner = connectedPath->begin();
    2920       class TesselPoint *CentralNode = *CircleRunner;
    29213006
    29223007      // re-create all triangles by going through connected points list
    2923       // advance two with CircleRunner and one with OtherCircleRunner
    2924       CircleRunner++;
    2925       CircleRunner++;
    2926       OtherCircleRunner++;
    2927       cout << Verbose(3) << "INFO: CentralNode is " << *CentralNode << "." << endl;
    2928       for (; (OtherCircleRunner != connectedPath->end()) && (CircleRunner != connectedPath->end()); (CircleRunner++), (OtherCircleRunner++)) {
    2929         cout << Verbose(4) << "INFO: CircleRunner's node is " << **CircleRunner << "." << endl;
    2930         cout << Verbose(4) << "INFO: OtherCircleRunner's node is " << **OtherCircleRunner << "." << endl;
    2931         *out << Verbose(3) << "INFO: Creating triangle " << CentralNode->Name << ", " << (*OtherCircleRunner)->Name << " and " << (*CircleRunner)->Name << "." << endl;
     3008      list<class BoundaryLineSet *> NewLines;
     3009      for (;!connectedPath->empty();) {
     3010        // search middle node with widest angle to next neighbours
     3011        EndNode = connectedPath->end();
     3012        smallestangle = 0.;
     3013        for (MiddleNode = connectedPath->begin(); MiddleNode != connectedPath->end(); MiddleNode++) {
     3014          cout << Verbose(3) << "INFO: MiddleNode is " << **MiddleNode << "." << endl;
     3015          // construct vectors to next and previous neighbour
     3016          StartNode = MiddleNode;
     3017          if (StartNode == connectedPath->begin())
     3018            StartNode = connectedPath->end();
     3019          StartNode--;
     3020          //cout << Verbose(3) << "INFO: StartNode is " << **StartNode << "." << endl;
     3021          Point.CopyVector((*StartNode)->node);
     3022          Point.SubtractVector((*MiddleNode)->node);
     3023          StartNode = MiddleNode;
     3024          StartNode++;
     3025          if (StartNode == connectedPath->end())
     3026            StartNode = connectedPath->begin();
     3027          //cout << Verbose(3) << "INFO: EndNode is " << **StartNode << "." << endl;
     3028          Reference.CopyVector((*StartNode)->node);
     3029          Reference.SubtractVector((*MiddleNode)->node);
     3030          OrthogonalVector.CopyVector((*MiddleNode)->node);
     3031          OrthogonalVector.SubtractVector(&OldPoint);
     3032          OrthogonalVector.MakeNormalVector(&Reference);
     3033          angle = GetAngle(Point, Reference, OrthogonalVector);
     3034          //if (angle < M_PI)  // no wrong-sided triangles, please?
     3035            if(fabs(angle - M_PI) < fabs(smallestangle - M_PI)) {  // get straightest angle (i.e. construct those triangles with smallest area first)
     3036              smallestangle = angle;
     3037              EndNode = MiddleNode;
     3038            }
     3039        }
     3040        MiddleNode = EndNode;
     3041        if (MiddleNode == connectedPath->end()) {
     3042          cout << Verbose(1) << "CRITICAL: Could not find a smallest angle!" << endl;
     3043          exit(255);
     3044        }
     3045        StartNode = MiddleNode;
     3046        if (StartNode == connectedPath->begin())
     3047          StartNode = connectedPath->end();
     3048        StartNode--;
     3049        EndNode++;
     3050        if (EndNode == connectedPath->end())
     3051          EndNode = connectedPath->begin();
     3052        cout << Verbose(4) << "INFO: StartNode is " << **StartNode << "." << endl;
     3053        cout << Verbose(4) << "INFO: MiddleNode is " << **MiddleNode << "." << endl;
     3054        cout << Verbose(4) << "INFO: EndNode is " << **EndNode << "." << endl;
     3055        *out << Verbose(3) << "INFO: Attempting to create triangle " << (*StartNode)->Name << ", " << (*MiddleNode)->Name << " and " << (*EndNode)->Name << "." << endl;
     3056        TriangleCandidates[0] = *StartNode;
     3057        TriangleCandidates[1] = *MiddleNode;
     3058        TriangleCandidates[2] = *EndNode;
     3059        triangle = GetPresentTriangle(out, TriangleCandidates);
     3060        if (triangle != NULL) {
     3061          cout << Verbose(1) << "WARNING: New triangle already present, skipping!" << endl;
     3062          StartNode++;
     3063          MiddleNode++;
     3064          EndNode++;
     3065          if (StartNode == connectedPath->end())
     3066            StartNode = connectedPath->begin();
     3067          if (MiddleNode == connectedPath->end())
     3068            MiddleNode = connectedPath->begin();
     3069          if (EndNode == connectedPath->end())
     3070            EndNode = connectedPath->begin();
     3071          continue;
     3072        }
    29323073        *out << Verbose(5) << "Adding new triangle points."<< endl;
    2933         TriangleCandidates[0] = CentralNode;
    2934         TriangleCandidates[1] = *OtherCircleRunner;
    2935         TriangleCandidates[2] = *CircleRunner;
    2936         triangle = GetPresentTriangle(out, TriangleCandidates);
    2937         AddTesselationPoint(CentralNode, 0);
    2938         AddTesselationPoint(*OtherCircleRunner, 1);
    2939         AddTesselationPoint(*CircleRunner, 2);
     3074        AddTesselationPoint(*StartNode, 0);
     3075        AddTesselationPoint(*MiddleNode, 1);
     3076        AddTesselationPoint(*EndNode, 2);
    29403077        *out << Verbose(5) << "Adding new triangle lines."<< endl;
    29413078        AddTesselationLine(TPS[0], TPS[1], 0);
    29423079        AddTesselationLine(TPS[0], TPS[2], 1);
     3080        NewLines.push_back(BLS[1]);
    29433081        AddTesselationLine(TPS[1], TPS[2], 2);
    29443082        BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     3083        BTS->GetNormalVector(NormalVector);
    29453084        AddTesselationTriangle();
    29463085        // calculate volume summand as a general tetraeder
    2947         for (int j=0;j<3;j++) {
    2948           TetraederVector[j].CopyVector(TPS[j]->node->node);
    2949           TetraederVector[j].SubtractVector(&OldPoint);
     3086        volume += CalculateVolumeofGeneralTetraeder(TPS[0]->node->node, TPS[1]->node->node, TPS[2]->node->node, &OldPoint);
     3087        // advance number
     3088        count++;
     3089
     3090        // prepare nodes for next triangle
     3091        StartNode = EndNode;
     3092        cout << Verbose(4) << "Removing " << **MiddleNode << " from closed path, remaining points: " << connectedPath->size() << "." << endl;
     3093        connectedPath->remove(*MiddleNode); // remove the middle node (it is surrounded by triangles)
     3094        if (connectedPath->size() == 2) { // we are done
     3095          connectedPath->remove(*StartNode); // remove the start node
     3096          connectedPath->remove(*EndNode); // remove the end node
     3097          break;
     3098        } else if (connectedPath->size() < 2) { // something's gone wrong!
     3099          cout << Verbose(1) << "CRITICAL: There are only two endpoints left!" << endl;
     3100          exit(255);
     3101        } else {
     3102          MiddleNode = StartNode;
     3103          MiddleNode++;
     3104          if (MiddleNode == connectedPath->end())
     3105            MiddleNode = connectedPath->begin();
     3106          EndNode = MiddleNode;
     3107          EndNode++;
     3108          if (EndNode == connectedPath->end())
     3109            EndNode = connectedPath->begin();
    29503110        }
    2951         OldPoint.CopyVector(&TetraederVector[0]);
    2952         OldPoint.VectorProduct(&TetraederVector[1]);
    2953         volume += 1./6. * fabs(OldPoint.ScalarProduct(&TetraederVector[2]));
    2954         // advance number
    2955         NumberRunner++;
    2956         count++;
    2957         if (NumberRunner == Candidates.end())
    2958           *out << Verbose(2) << "WARN: Maximum of numbers reached!" << endl;
    29593111      }
     3112      // maximize the inner lines (we preferentially created lines with a huge angle, which is for the tesselation not wanted though useful for the closing)
     3113      if (NewLines.size() > 1) {
     3114        list<class BoundaryLineSet *>::iterator Candidate;
     3115        class BoundaryLineSet *OtherBase = NULL;
     3116        double tmp, maxgain;
     3117        do {
     3118          maxgain = 0;
     3119          for(list<class BoundaryLineSet *>::iterator Runner = NewLines.begin(); Runner != NewLines.end(); Runner++) {
     3120            tmp = PickFarthestofTwoBaselines(out, *Runner);
     3121            if (maxgain < tmp) {
     3122              maxgain = tmp;
     3123              Candidate = Runner;
     3124            }
     3125          }
     3126          if (maxgain != 0) {
     3127            volume += maxgain;
     3128            cout << Verbose(3) << "Flipping baseline with highest volume" << **Candidate << "." << endl;
     3129            OtherBase = FlipBaseline(out, *Candidate);
     3130            NewLines.erase(Candidate);
     3131            NewLines.push_back(OtherBase);
     3132          }
     3133        } while (maxgain != 0.);
     3134      }
     3135
    29603136      ListOfClosedPaths->remove(connectedPath);
    29613137      delete(connectedPath);
     
    29713147    *out << Verbose(1) << "No need to create any triangles." << endl;
    29723148  }
    2973 
    29743149  delete(ListOfClosedPaths);
    29753150
     3151  *out << Verbose(1) << "Removed volume is " << volume << "." << endl;
     3152
    29763153  return volume;
    29773154};
    29783155
    29793156
    2980 
    2981 /** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
    2982  * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
    2983  * make it bigger (i.e. closing one (the baseline) and opening two new ones).
    2984  * \param TPS[3] nodes of the triangle
    2985  * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
    2986  */
    2987 bool CheckLineCriteriaForDegeneratedTriangle(class BoundaryPointSet *nodes[3])
    2988 {
    2989   bool result = false;
    2990   int counter = 0;
    2991 
    2992   // check all three points
    2993   for (int i=0;i<3;i++)
    2994     for (int j=i+1; j<3; j++) {
    2995       if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) {  // there already is a line
    2996         LineMap::iterator FindLine;
    2997         pair<LineMap::iterator,LineMap::iterator> FindPair;
    2998         FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
    2999         for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
    3000           // If there is a line with less than two attached triangles, we don't need a new line.
    3001           if (FindLine->second->triangles.size() < 2) {
    3002             counter++;
    3003             break;  // increase counter only once per edge
    3004           }
    3005         }
    3006       } else { // no line
    3007         cout << Verbose(1) << "The line between " << nodes[i] << " and " << nodes[j] << " is not yet present, hence no need for a degenerate triangle." << endl;
    3008         result = true;
    3009       }
    3010     }
    3011   if (counter > 1) {
    3012     cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
    3013     result = true;
    3014   }
    3015   return result;
    3016 };
    3017 
    3018 
    3019 /** Sort function for the candidate list.
    3020  */
    3021 bool SortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2)
    3022 {
    3023   Vector BaseLineVector, OrthogonalVector, helper;
    3024   if (candidate1->BaseLine != candidate2->BaseLine) {  // sanity check
    3025     cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
    3026     //return false;
    3027     exit(1);
    3028   }
    3029   // create baseline vector
    3030   BaseLineVector.CopyVector(candidate1->BaseLine->endpoints[1]->node->node);
    3031   BaseLineVector.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
    3032   BaseLineVector.Normalize();
    3033 
    3034   // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!)
    3035   helper.CopyVector(candidate1->BaseLine->endpoints[0]->node->node);
    3036   helper.SubtractVector(candidate1->point->node);
    3037   OrthogonalVector.CopyVector(&helper);
    3038   helper.VectorProduct(&BaseLineVector);
    3039   OrthogonalVector.SubtractVector(&helper);
    3040   OrthogonalVector.Normalize();
    3041 
    3042   // calculate both angles and correct with in-plane vector
    3043   helper.CopyVector(candidate1->point->node);
    3044   helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
    3045   double phi = BaseLineVector.Angle(&helper);
    3046   if (OrthogonalVector.ScalarProduct(&helper) > 0) {
    3047     phi = 2.*M_PI - phi;
    3048   }
    3049   helper.CopyVector(candidate2->point->node);
    3050   helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
    3051   double psi = BaseLineVector.Angle(&helper);
    3052   if (OrthogonalVector.ScalarProduct(&helper) > 0) {
    3053     psi = 2.*M_PI - psi;
    3054   }
    3055 
    3056   cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
    3057   cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
    3058 
    3059   // return comparison
    3060   return phi < psi;
    3061 };
    3062 
    3063 /**
    3064  * Finds the point which is second closest to the provided one.
    3065  *
    3066  * @param Point to which to find the second closest other point
    3067  * @param linked cell structure
    3068  *
    3069  * @return point which is second closest to the provided one
    3070  */
    3071 TesselPoint* FindSecondClosestPoint(const Vector* Point, LinkedCell* LC)
    3072 {
    3073   LinkedNodes *List = NULL;
    3074   TesselPoint* closestPoint = NULL;
    3075   TesselPoint* secondClosestPoint = NULL;
    3076   double distance = 1e16;
    3077   double secondDistance = 1e16;
    3078   Vector helper;
    3079   int N[NDIM], Nlower[NDIM], Nupper[NDIM];
    3080 
    3081   LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
    3082   for(int i=0;i<NDIM;i++) // store indices of this cell
    3083     N[i] = LC->n[i];
    3084   cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
    3085 
    3086   LC->GetNeighbourBounds(Nlower, Nupper);
    3087   //cout << endl;
    3088   for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
    3089     for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
    3090       for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
    3091         List = LC->GetCurrentCell();
    3092         cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
    3093         if (List != NULL) {
    3094           for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
    3095             helper.CopyVector(Point);
    3096             helper.SubtractVector((*Runner)->node);
    3097             double currentNorm = helper. Norm();
    3098             if (currentNorm < distance) {
    3099               // remember second point
    3100               secondDistance = distance;
    3101               secondClosestPoint = closestPoint;
    3102               // mark down new closest point
    3103               distance = currentNorm;
    3104               closestPoint = (*Runner);
    3105               cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
    3106             }
    3107           }
    3108         } else {
    3109           cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
    3110             << LC->n[2] << " is invalid!" << endl;
    3111         }
    3112       }
    3113 
    3114   return secondClosestPoint;
    3115 };
    3116 
    3117 /**
    3118  * Finds the point which is closest to the provided one.
    3119  *
    3120  * @param Point to which to find the closest other point
    3121  * @param SecondPoint the second closest other point on return, NULL if none found
    3122  * @param linked cell structure
    3123  *
    3124  * @return point which is closest to the provided one, NULL if none found
    3125  */
    3126 TesselPoint* FindClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC)
    3127 {
    3128   LinkedNodes *List = NULL;
    3129   TesselPoint* closestPoint = NULL;
    3130   SecondPoint = NULL;
    3131   double distance = 1e16;
    3132   double secondDistance = 1e16;
    3133   Vector helper;
    3134   int N[NDIM], Nlower[NDIM], Nupper[NDIM];
    3135 
    3136   LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
    3137   for(int i=0;i<NDIM;i++) // store indices of this cell
    3138     N[i] = LC->n[i];
    3139   cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
    3140 
    3141   LC->GetNeighbourBounds(Nlower, Nupper);
    3142   //cout << endl;
    3143   for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
    3144     for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
    3145       for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
    3146         List = LC->GetCurrentCell();
    3147         cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
    3148         if (List != NULL) {
    3149           for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
    3150             helper.CopyVector(Point);
    3151             helper.SubtractVector((*Runner)->node);
    3152             double currentNorm = helper. Norm();
    3153             if (currentNorm < distance) {
    3154               secondDistance = distance;
    3155               SecondPoint = closestPoint;
    3156               distance = currentNorm;
    3157               closestPoint = (*Runner);
    3158               cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
    3159             } else if (currentNorm < secondDistance) {
    3160               secondDistance = currentNorm;
    3161               SecondPoint = (*Runner);
    3162               cout << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
    3163             }
    3164           }
    3165         } else {
    3166           cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
    3167             << LC->n[2] << " is invalid!" << endl;
    3168         }
    3169       }
    3170 
    3171   return closestPoint;
    3172 };
    31733157
    31743158/**
     
    32073191              FindTriangle = FindLine->second->triangles.begin();
    32083192              for (; FindTriangle != FindLine->second->triangles.end(); FindTriangle++) {
    3209                 if ((
    3210                   (FindTriangle->second->endpoints[0] == TrianglePoints[0])
    3211                     || (FindTriangle->second->endpoints[0] == TrianglePoints[1])
    3212                     || (FindTriangle->second->endpoints[0] == TrianglePoints[2])
    3213                   ) && (
    3214                     (FindTriangle->second->endpoints[1] == TrianglePoints[0])
    3215                     || (FindTriangle->second->endpoints[1] == TrianglePoints[1])
    3216                     || (FindTriangle->second->endpoints[1] == TrianglePoints[2])
    3217                   ) && (
    3218                     (FindTriangle->second->endpoints[2] == TrianglePoints[0])
    3219                     || (FindTriangle->second->endpoints[2] == TrianglePoints[1])
    3220                     || (FindTriangle->second->endpoints[2] == TrianglePoints[2])
    3221                   )
    3222                 ) {
     3193                if (FindTriangle->second->IsPresentTupel(TrianglePoints)) {
    32233194                  result->push_back(FindTriangle->second);
    32243195                }
     
    32383209
    32393210/**
     3211 * Finds all degenerated lines within the tesselation structure.
     3212 *
     3213 * @return map of keys of degenerated line pairs, each line occurs twice
     3214 *         in the list, once as key and once as value
     3215 */
     3216map<int, int> * Tesselation::FindAllDegeneratedLines()
     3217{
     3218  map<int, class BoundaryLineSet *> AllLines;
     3219  map<int, int> * DegeneratedLines = new map<int, int>;
     3220
     3221  // sanity check
     3222  if (LinesOnBoundary.empty()) {
     3223    cout << Verbose(1) << "Warning: FindAllDegeneratedTriangles() was called without any tesselation structure.";
     3224    return DegeneratedLines;
     3225  }
     3226
     3227  LineMap::iterator LineRunner1;
     3228  pair<LineMap::iterator, bool> tester;
     3229  for (LineRunner1 = LinesOnBoundary.begin(); LineRunner1 != LinesOnBoundary.end(); ++LineRunner1) {
     3230    tester = AllLines.insert( pair<int,BoundaryLineSet *> (LineRunner1->second->endpoints[0]->Nr, LineRunner1->second) );
     3231    if ((!tester.second) && (tester.first->second->endpoints[1]->Nr == LineRunner1->second->endpoints[1]->Nr)) { // found degenerated line
     3232      DegeneratedLines->insert ( pair<int, int> (LineRunner1->second->Nr, tester.first->second->Nr) );
     3233      DegeneratedLines->insert ( pair<int, int> (tester.first->second->Nr, LineRunner1->second->Nr) );
     3234    }
     3235  }
     3236
     3237  AllLines.clear();
     3238
     3239  cout << Verbose(1) << "FindAllDegeneratedLines() found " << DegeneratedLines->size() << " lines." << endl;
     3240  map<int,int>::iterator it;
     3241  for (it = DegeneratedLines->begin(); it != DegeneratedLines->end(); it++)
     3242      cout << Verbose(2) << (*it).first << " => " << (*it).second << endl;
     3243
     3244  return DegeneratedLines;
     3245}
     3246
     3247/**
    32403248 * Finds all degenerated triangles within the tesselation structure.
    32413249 *
     
    32433251 *         in the list, once as key and once as value
    32443252 */
    3245 map<int, int> Tesselation::FindAllDegeneratedTriangles()
    3246 {
    3247   map<int, int> DegeneratedTriangles;
    3248 
    3249   // sanity check
    3250   if (LinesOnBoundary.empty()) {
    3251     cout << Verbose(1) << "Warning: FindAllDegeneratedTriangles() was called without any tesselation structure.";
    3252     return DegeneratedTriangles;
    3253   }
    3254 
    3255   LineMap::iterator LineRunner1, LineRunner2;
    3256 
    3257   for (LineRunner1 = LinesOnBoundary.begin(); LineRunner1 != LinesOnBoundary.end(); ++LineRunner1) {
    3258     for (LineRunner2 = LinesOnBoundary.begin(); LineRunner2 != LinesOnBoundary.end(); ++LineRunner2) {
    3259       if ((LineRunner1->second != LineRunner2->second)
    3260         && (LineRunner1->second->endpoints[0] == LineRunner2->second->endpoints[0])
    3261         && (LineRunner1->second->endpoints[1] == LineRunner2->second->endpoints[1])
    3262       ) {
    3263         TriangleMap::iterator TriangleRunner1 = LineRunner1->second->triangles.begin(),
    3264           TriangleRunner2 = LineRunner2->second->triangles.begin();
    3265 
    3266         for (; TriangleRunner1 != LineRunner1->second->triangles.end(); ++TriangleRunner1) {
    3267           for (; TriangleRunner2 != LineRunner2->second->triangles.end(); ++TriangleRunner2) {
    3268             if ((TriangleRunner1->second != TriangleRunner2->second)
    3269               && (TriangleRunner1->second->endpoints[0] == TriangleRunner2->second->endpoints[0])
    3270               && (TriangleRunner1->second->endpoints[1] == TriangleRunner2->second->endpoints[1])
    3271               && (TriangleRunner1->second->endpoints[2] == TriangleRunner2->second->endpoints[2])
    3272             ) {
    3273               DegeneratedTriangles[TriangleRunner1->second->Nr] = TriangleRunner2->second->Nr;
    3274               DegeneratedTriangles[TriangleRunner2->second->Nr] = TriangleRunner1->second->Nr;
    3275             }
    3276           }
     3253map<int, int> * Tesselation::FindAllDegeneratedTriangles()
     3254{
     3255  map<int, int> * DegeneratedLines = FindAllDegeneratedLines();
     3256  map<int, int> * DegeneratedTriangles = new map<int, int>;
     3257
     3258  TriangleMap::iterator TriangleRunner1, TriangleRunner2;
     3259  LineMap::iterator Liner;
     3260  class BoundaryLineSet *line1 = NULL, *line2 = NULL;
     3261
     3262  for (map<int, int>::iterator LineRunner = DegeneratedLines->begin(); LineRunner != DegeneratedLines->end(); ++LineRunner) {
     3263    // run over both lines' triangles
     3264    Liner = LinesOnBoundary.find(LineRunner->first);
     3265    if (Liner != LinesOnBoundary.end())
     3266      line1 = Liner->second;
     3267    Liner = LinesOnBoundary.find(LineRunner->second);
     3268    if (Liner != LinesOnBoundary.end())
     3269      line2 = Liner->second;
     3270    for (TriangleRunner1 = line1->triangles.begin(); TriangleRunner1 != line1->triangles.end(); ++TriangleRunner1) {
     3271      for (TriangleRunner2 = line2->triangles.begin(); TriangleRunner2 != line2->triangles.end(); ++TriangleRunner2) {
     3272        if ((TriangleRunner1->second != TriangleRunner2->second)
     3273          && (TriangleRunner1->second->IsPresentTupel(TriangleRunner2->second))) {
     3274          DegeneratedTriangles->insert( pair<int, int> (TriangleRunner1->second->Nr, TriangleRunner2->second->Nr) );
     3275          DegeneratedTriangles->insert( pair<int, int> (TriangleRunner2->second->Nr, TriangleRunner1->second->Nr) );
    32773276        }
    32783277      }
    32793278    }
    32803279  }
    3281 
    3282   cout << Verbose(1) << "FindAllDegeneratedTriangles() found " << DegeneratedTriangles.size() << " triangles." << endl;
     3280  delete(DegeneratedLines);
     3281
     3282  cout << Verbose(1) << "FindAllDegeneratedTriangles() found " << DegeneratedTriangles->size() << " triangles:" << endl;
    32833283  map<int,int>::iterator it;
    3284   for (it = DegeneratedTriangles.begin(); it != DegeneratedTriangles.end(); it++)
     3284  for (it = DegeneratedTriangles->begin(); it != DegeneratedTriangles->end(); it++)
    32853285      cout << Verbose(2) << (*it).first << " => " << (*it).second << endl;
    32863286
     
    32943294void Tesselation::RemoveDegeneratedTriangles()
    32953295{
    3296   map<int, int> DegeneratedTriangles = FindAllDegeneratedTriangles();
    3297 
    3298   for (map<int, int>::iterator TriangleKeyRunner = DegeneratedTriangles.begin();
    3299     TriangleKeyRunner != DegeneratedTriangles.end(); ++TriangleKeyRunner
     3296  map<int, int> * DegeneratedTriangles = FindAllDegeneratedTriangles();
     3297  TriangleMap::iterator finder;
     3298  BoundaryTriangleSet *triangle = NULL, *partnerTriangle = NULL;
     3299  int count  = 0;
     3300
     3301  for (map<int, int>::iterator TriangleKeyRunner = DegeneratedTriangles->begin();
     3302    TriangleKeyRunner != DegeneratedTriangles->end(); ++TriangleKeyRunner
    33003303  ) {
    3301     BoundaryTriangleSet *triangle = TrianglesOnBoundary.find(TriangleKeyRunner->first)->second,
    3302       *partnerTriangle = TrianglesOnBoundary.find(TriangleKeyRunner->second)->second;
     3304    finder = TrianglesOnBoundary.find(TriangleKeyRunner->first);
     3305    if (finder != TrianglesOnBoundary.end())
     3306      triangle = finder->second;
     3307    else
     3308      break;
     3309    finder = TrianglesOnBoundary.find(TriangleKeyRunner->second);
     3310    if (finder != TrianglesOnBoundary.end())
     3311      partnerTriangle = finder->second;
     3312    else
     3313      break;
    33033314
    33043315    bool trianglesShareLine = false;
     
    33123323      && (triangle->endpoints[0]->LinesCount > 2)
    33133324    ) {
     3325      // check whether we have to fix lines
     3326      BoundaryTriangleSet *Othertriangle = NULL;
     3327      BoundaryTriangleSet *OtherpartnerTriangle = NULL;
     3328      TriangleMap::iterator TriangleRunner;
     3329      for (int i = 0; i < 3; ++i)
     3330        for (int j = 0; j < 3; ++j)
     3331          if (triangle->lines[i] != partnerTriangle->lines[j]) {
     3332            // get the other two triangles
     3333            for (TriangleRunner = triangle->lines[i]->triangles.begin(); TriangleRunner != triangle->lines[i]->triangles.end(); ++TriangleRunner)
     3334              if (TriangleRunner->second != triangle) {
     3335                Othertriangle = TriangleRunner->second;
     3336              }
     3337            for (TriangleRunner = partnerTriangle->lines[i]->triangles.begin(); TriangleRunner != partnerTriangle->lines[i]->triangles.end(); ++TriangleRunner)
     3338              if (TriangleRunner->second != partnerTriangle) {
     3339                OtherpartnerTriangle = TriangleRunner->second;
     3340              }
     3341            /// interchanges their lines so that triangle->lines[i] == partnerTriangle->lines[j]
     3342            // the line of triangle receives the degenerated ones
     3343            triangle->lines[i]->triangles.erase(Othertriangle->Nr);
     3344            triangle->lines[i]->triangles.insert( TrianglePair( partnerTriangle->Nr, partnerTriangle) );
     3345            for (int k=0;k<3;k++)
     3346              if (triangle->lines[i] == Othertriangle->lines[k]) {
     3347                Othertriangle->lines[k] = partnerTriangle->lines[j];
     3348                break;
     3349              }
     3350            // the line of partnerTriangle receives the non-degenerated ones
     3351            partnerTriangle->lines[j]->triangles.erase( partnerTriangle->Nr);
     3352            partnerTriangle->lines[j]->triangles.insert( TrianglePair( Othertriangle->Nr, Othertriangle) );
     3353            partnerTriangle->lines[j] = triangle->lines[i];
     3354          }
     3355
     3356      // erase the pair
     3357      count += (int) DegeneratedTriangles->erase(triangle->Nr);
    33143358      cout << Verbose(1) << "RemoveDegeneratedTriangles() removes triangle " << *triangle << "." << endl;
    33153359      RemoveTesselationTriangle(triangle);
     3360      count += (int) DegeneratedTriangles->erase(partnerTriangle->Nr);
    33163361      cout << Verbose(1) << "RemoveDegeneratedTriangles() removes triangle " << *partnerTriangle << "." << endl;
    33173362      RemoveTesselationTriangle(partnerTriangle);
    3318       DegeneratedTriangles.erase(DegeneratedTriangles.find(partnerTriangle->Nr));
    33193363    } else {
    33203364      cout << Verbose(1) << "RemoveDegeneratedTriangles() does not remove triangle " << *triangle
     
    33233367    }
    33243368  }
     3369  delete(DegeneratedTriangles);
     3370
     3371  cout << Verbose(1) << "RemoveDegeneratedTriangles() removed " << count << " triangles:" << endl;
    33253372}
    33263373
    3327 /** Gets the angle between a point and a reference relative to the provided center.
    3328  * We have two shanks point and reference between which the angle is calculated
    3329  * and by scalar product with OrthogonalVector we decide the interval.
    3330  * @param point to calculate the angle for
    3331  * @param reference to which to calculate the angle
    3332  * @param OrthogonalVector points in direction of [pi,2pi] interval
    3333  *
    3334  * @return angle between point and reference
    3335  */
    3336 double GetAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector)
    3337 {
    3338   if (reference.IsZero())
    3339     return M_PI;
    3340 
    3341   // calculate both angles and correct with in-plane vector
    3342   if (point.IsZero())
    3343     return M_PI;
    3344   double phi = point.Angle(&reference);
    3345   if (OrthogonalVector.ScalarProduct(&point) > 0) {
    3346     phi = 2.*M_PI - phi;
    3347   }
    3348 
    3349   cout << Verbose(4) << "INFO: " << point << " has angle " << phi << " with respect to reference " << reference << "." << endl;
    3350 
    3351   return phi;
    3352 }
    3353 
     3374/** Adds an outside Tesselpoint to the envelope via (two) degenerated triangles.
     3375 * We look for the closest point on the boundary, we look through its connected boundary lines and
     3376 * seek the one with the minimum angle between its center point and the new point and this base line.
     3377 * We open up the line by adding a degenerated triangle, whose other side closes the base line again.
     3378 * \param *out output stream for debugging
     3379 * \param *point point to add
     3380 * \param *LC Linked Cell structure to find nearest point
     3381 */
     3382void Tesselation::AddBoundaryPointByDegeneratedTriangle(ofstream *out, class TesselPoint *point, LinkedCell *LC)
     3383{
     3384  *out << Verbose(2) << "Begin of AddBoundaryPointByDegeneratedTriangle" << endl;
     3385
     3386  // find nearest boundary point
     3387  class TesselPoint *BackupPoint = NULL;
     3388  class TesselPoint *NearestPoint = FindClosestPoint(point->node, BackupPoint, LC);
     3389  class BoundaryPointSet *NearestBoundaryPoint = NULL;
     3390  PointMap::iterator PointRunner;
     3391
     3392  if (NearestPoint == point)
     3393    NearestPoint = BackupPoint;
     3394  PointRunner = PointsOnBoundary.find(NearestPoint->nr);
     3395  if (PointRunner != PointsOnBoundary.end()) {
     3396    NearestBoundaryPoint = PointRunner->second;
     3397  } else {
     3398    *out << Verbose(1) << "ERROR: I cannot find the boundary point." << endl;
     3399    return;
     3400  }
     3401  *out << Verbose(2) << "Nearest point on boundary is " << NearestPoint->Name << "." << endl;
     3402
     3403  // go through its lines and find the best one to split
     3404  Vector CenterToPoint;
     3405  Vector BaseLine;
     3406  double angle, BestAngle = 0.;
     3407  class BoundaryLineSet *BestLine = NULL;
     3408  for (LineMap::iterator Runner = NearestBoundaryPoint->lines.begin(); Runner != NearestBoundaryPoint->lines.end(); Runner++) {
     3409    BaseLine.CopyVector(Runner->second->endpoints[0]->node->node);
     3410    BaseLine.SubtractVector(Runner->second->endpoints[1]->node->node);
     3411    CenterToPoint.CopyVector(Runner->second->endpoints[0]->node->node);
     3412    CenterToPoint.AddVector(Runner->second->endpoints[1]->node->node);
     3413    CenterToPoint.Scale(0.5);
     3414    CenterToPoint.SubtractVector(point->node);
     3415    angle = CenterToPoint.Angle(&BaseLine);
     3416    if (fabs(angle - M_PI/2.) < fabs(BestAngle - M_PI/2.)) {
     3417      BestAngle = angle;
     3418      BestLine = Runner->second;
     3419    }
     3420  }
     3421
     3422  // remove one triangle from the chosen line
     3423  class BoundaryTriangleSet *TempTriangle = (BestLine->triangles.begin())->second;
     3424  BestLine->triangles.erase(TempTriangle->Nr);
     3425  int nr = -1;
     3426  for (int i=0;i<3; i++) {
     3427    if (TempTriangle->lines[i] == BestLine) {
     3428      nr = i;
     3429      break;
     3430    }
     3431  }
     3432
     3433  // create new triangle to connect point (connects automatically with the missing spot of the chosen line)
     3434  *out << Verbose(5) << "Adding new triangle points."<< endl;
     3435  AddTesselationPoint((BestLine->endpoints[0]->node), 0);
     3436  AddTesselationPoint((BestLine->endpoints[1]->node), 1);
     3437  AddTesselationPoint(point, 2);
     3438  *out << Verbose(5) << "Adding new triangle lines."<< endl;
     3439  AddTesselationLine(TPS[0], TPS[1], 0);
     3440  AddTesselationLine(TPS[0], TPS[2], 1);
     3441  AddTesselationLine(TPS[1], TPS[2], 2);
     3442  BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     3443  BTS->GetNormalVector(TempTriangle->NormalVector);
     3444  BTS->NormalVector.Scale(-1.);
     3445  *out << Verbose(3) << "INFO: NormalVector of new triangle is " << BTS->NormalVector << "." << endl;
     3446  AddTesselationTriangle();
     3447
     3448  // create other side of this triangle and close both new sides of the first created triangle
     3449  *out << Verbose(5) << "Adding new triangle points."<< endl;
     3450  AddTesselationPoint((BestLine->endpoints[0]->node), 0);
     3451  AddTesselationPoint((BestLine->endpoints[1]->node), 1);
     3452  AddTesselationPoint(point, 2);
     3453  *out << Verbose(5) << "Adding new triangle lines."<< endl;
     3454  AddTesselationLine(TPS[0], TPS[1], 0);
     3455  AddTesselationLine(TPS[0], TPS[2], 1);
     3456  AddTesselationLine(TPS[1], TPS[2], 2);
     3457  BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
     3458  BTS->GetNormalVector(TempTriangle->NormalVector);
     3459  *out << Verbose(3) << "INFO: NormalVector of other new triangle is " << BTS->NormalVector << "." << endl;
     3460  AddTesselationTriangle();
     3461
     3462  // add removed triangle to the last open line of the second triangle
     3463  for (int i=0;i<3;i++) { // look for the same line as BestLine (only it's its degenerated companion)
     3464    if ((BTS->lines[i]->ContainsBoundaryPoint(BestLine->endpoints[0])) && (BTS->lines[i]->ContainsBoundaryPoint(BestLine->endpoints[1]))) {
     3465      if (BestLine == BTS->lines[i]){
     3466        *out << Verbose(1) << "CRITICAL: BestLine is same as found line, something's wrong here!" << endl;
     3467        exit(255);
     3468      }
     3469      BTS->lines[i]->triangles.insert( pair<int, class BoundaryTriangleSet *> (TempTriangle->Nr, TempTriangle) );
     3470      TempTriangle->lines[nr] = BTS->lines[i];
     3471      break;
     3472    }
     3473  }
     3474
     3475  // exit
     3476  *out << Verbose(2) << "End of AddBoundaryPointByDegeneratedTriangle" << endl;
     3477};
     3478
     3479/** Writes the envelope to file.
     3480 * \param *out otuput stream for debugging
     3481 * \param *filename basename of output file
     3482 * \param *cloud PointCloud structure with all nodes
     3483 */
     3484void Tesselation::Output(ofstream *out, const char *filename, PointCloud *cloud)
     3485{
     3486  ofstream *tempstream = NULL;
     3487  string NameofTempFile;
     3488  char NumberName[255];
     3489
     3490  if (LastTriangle != NULL) {
     3491    sprintf(NumberName, "-%04d-%s_%s_%s", (int)TrianglesOnBoundary.size(), LastTriangle->endpoints[0]->node->Name, LastTriangle->endpoints[1]->node->Name, LastTriangle->endpoints[2]->node->Name);
     3492    if (DoTecplotOutput) {
     3493      string NameofTempFile(filename);
     3494      NameofTempFile.append(NumberName);
     3495      for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
     3496      NameofTempFile.erase(npos, 1);
     3497      NameofTempFile.append(TecplotSuffix);
     3498      *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
     3499      tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
     3500      WriteTecplotFile(out, tempstream, this, cloud, TriangleFilesWritten);
     3501      tempstream->close();
     3502      tempstream->flush();
     3503      delete(tempstream);
     3504    }
     3505
     3506    if (DoRaster3DOutput) {
     3507      string NameofTempFile(filename);
     3508      NameofTempFile.append(NumberName);
     3509      for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
     3510      NameofTempFile.erase(npos, 1);
     3511      NameofTempFile.append(Raster3DSuffix);
     3512      *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
     3513      tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
     3514      WriteRaster3dFile(out, tempstream, this, cloud);
     3515      IncludeSphereinRaster3D(out, tempstream, this, cloud);
     3516      tempstream->close();
     3517      tempstream->flush();
     3518      delete(tempstream);
     3519    }
     3520  }
     3521  if (DoTecplotOutput || DoRaster3DOutput)
     3522    TriangleFilesWritten++;
     3523};
  • src/tesselation.hpp

    r91e7e4a r57066a  
    3434class PointCloud;
    3535class Tesselation;
     36
     37#define DoTecplotOutput 1
     38#define DoRaster3DOutput 1
     39#define DoVRMLOutput 1
     40#define TecplotSuffix ".dat"
     41#define Raster3DSuffix ".r3d"
     42#define VRMLSUffix ".wrl"
    3643
    3744// ======================================================= some template functions =========================================
     
    115122
    116123    void GetNormalVector(Vector &NormalVector);
     124    void GetCenter(Vector *center);
    117125    bool GetIntersectionInsideTriangle(ofstream *out, Vector *MolCenter, Vector *x, Vector *Intersection);
    118126    bool ContainsBoundaryLine(class BoundaryLineSet *line);
     
    120128    class BoundaryPointSet *GetThirdEndpoint(class BoundaryLineSet *line);
    121129    bool IsPresentTupel(class BoundaryPointSet *Points[3]);
    122     void GetCenter(Vector *center);
     130    bool IsPresentTupel(class BoundaryTriangleSet *T);
    123131
    124132    class BoundaryPointSet *endpoints[3];
     
    200208    void RemoveTesselationPoint(class BoundaryPointSet *point);
    201209
    202     bool IsInside(Vector *pointer);
    203210    class BoundaryPointSet *GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2);
    204211
    205212    // concave envelope
    206213    void FindStartingTriangle(ofstream *out, const double RADIUS, class LinkedCell *LC);
    207     void FindSecondPointForTesselation(class TesselPoint* a, class TesselPoint* Candidate, Vector Oben, class TesselPoint*& OptCandidate, double Storage[3], double RADIUS, class LinkedCell *LC);
     214    void FindSecondPointForTesselation(class TesselPoint* a, Vector Oben, class TesselPoint*& OptCandidate, double Storage[3], double RADIUS, class LinkedCell *LC);
    208215    void FindThirdPointForTesselation(Vector NormalVector, Vector SearchDirection, Vector OldSphereCenter, class BoundaryLineSet *BaseLine, class TesselPoint *ThirdNode, CandidateList* &candidates, double *ShortestAngle, const double RADIUS, class LinkedCell *LC);
    209     bool FindNextSuitableTriangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, int N, LinkedCell *LC);
     216    bool FindNextSuitableTriangle(ofstream *out, BoundaryLineSet &Line, BoundaryTriangleSet &T, const double& RADIUS, LinkedCell *LC);
    210217    int CheckPresenceOfTriangle(ofstream *out, class TesselPoint *Candidates[3]);
    211218    class BoundaryTriangleSet * GetPresentTriangle(ofstream *out, TesselPoint *Candidates[3]);
     
    216223    bool InsertStraddlingPoints(ofstream *out, PointCloud *cloud, LinkedCell *LC);
    217224    double RemovePointFromTesselatedSurface(ofstream *out, class BoundaryPointSet *point);
    218     bool FlipBaseline(ofstream *out, class BoundaryLineSet *Base);
    219     bool PickFarthestofTwoBaselines(ofstream *out, class BoundaryLineSet *Base);
     225    class BoundaryLineSet * FlipBaseline(ofstream *out, class BoundaryLineSet *Base);
     226    double PickFarthestofTwoBaselines(ofstream *out, class BoundaryLineSet *Base);
    220227    class BoundaryPointSet *IsConvexRectangle(ofstream *out, class BoundaryLineSet *Base);
    221     map<int, int> FindAllDegeneratedTriangles();
     228    map<int, int> * FindAllDegeneratedTriangles();
     229    map<int, int> * FindAllDegeneratedLines();
    222230    void RemoveDegeneratedTriangles();
     231    void AddBoundaryPointByDegeneratedTriangle(ofstream *out, class TesselPoint *point, LinkedCell *LC);
    223232
    224233    set<TesselPoint*> * GetAllConnectedPoints(ofstream *out, TesselPoint* Point);
     
    239248    void PrintAllBoundaryTriangles(ofstream *out);
    240249
     250    // store envelope in file
     251    void Output(ofstream *out, const char *filename, PointCloud *cloud);
    241252
    242253    PointMap PointsOnBoundary;
     
    261272    class BoundaryLineSet *BLS[3];
    262273    class BoundaryTriangleSet *BTS;
     274    class BoundaryTriangleSet *LastTriangle;
     275    int TriangleFilesWritten;
    263276
    264277  private:
     
    268281};
    269282
    270 bool CheckLineCriteriaForDegeneratedTriangle(class BoundaryPointSet *nodes[3]);
    271 bool SortCandidates(class CandidateForTesselation* candidate1, class CandidateForTesselation* candidate2);
    272 TesselPoint* FindClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC);
    273 TesselPoint* FindSecondClosestPoint(const Vector*, LinkedCell*);
    274 double GetAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector);
    275 Vector * GetClosestPointBetweenLine(ofstream *out, class BoundaryLineSet *Base, class BoundaryLineSet *OtherBase);
    276283
    277284#endif /* TESSELATION_HPP_ */
  • src/tesselationhelpers.cpp

    r91e7e4a r57066a  
    388388};
    389389
     390/** Gets the angle between a point and a reference relative to the provided center.
     391 * We have two shanks point and reference between which the angle is calculated
     392 * and by scalar product with OrthogonalVector we decide the interval.
     393 * @param point to calculate the angle for
     394 * @param reference to which to calculate the angle
     395 * @param OrthogonalVector points in direction of [pi,2pi] interval
     396 *
     397 * @return angle between point and reference
     398 */
     399double GetAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector)
     400{
     401  if (reference.IsZero())
     402    return M_PI;
     403
     404  // calculate both angles and correct with in-plane vector
     405  if (point.IsZero())
     406    return M_PI;
     407  double phi = point.Angle(&reference);
     408  if (OrthogonalVector.ScalarProduct(&point) > 0) {
     409    phi = 2.*M_PI - phi;
     410  }
     411
     412  cout << Verbose(4) << "INFO: " << point << " has angle " << phi << " with respect to reference " << reference << "." << endl;
     413
     414  return phi;
     415}
     416
    390417
    391418/** Calculates the volume of a general tetraeder.
     
    412439};
    413440
     441
     442/** Checks for a new special triangle whether one of its edges is already present with one one triangle connected.
     443 * This enforces that special triangles (i.e. degenerated ones) should at last close the open-edge frontier and not
     444 * make it bigger (i.e. closing one (the baseline) and opening two new ones).
     445 * \param TPS[3] nodes of the triangle
     446 * \return true - there is such a line (i.e. creation of degenerated triangle is valid), false - no such line (don't create)
     447 */
     448bool CheckLineCriteriaForDegeneratedTriangle(class BoundaryPointSet *nodes[3])
     449{
     450  bool result = false;
     451  int counter = 0;
     452
     453  // check all three points
     454  for (int i=0;i<3;i++)
     455    for (int j=i+1; j<3; j++) {
     456      if (nodes[i]->lines.find(nodes[j]->node->nr) != nodes[i]->lines.end()) {  // there already is a line
     457        LineMap::iterator FindLine;
     458        pair<LineMap::iterator,LineMap::iterator> FindPair;
     459        FindPair = nodes[i]->lines.equal_range(nodes[j]->node->nr);
     460        for (FindLine = FindPair.first; FindLine != FindPair.second; ++FindLine) {
     461          // If there is a line with less than two attached triangles, we don't need a new line.
     462          if (FindLine->second->triangles.size() < 2) {
     463            counter++;
     464            break;  // increase counter only once per edge
     465          }
     466        }
     467      } else { // no line
     468        cout << Verbose(1) << "The line between " << *nodes[i] << " and " << *nodes[j] << " is not yet present, hence no need for a degenerate triangle." << endl;
     469        result = true;
     470      }
     471    }
     472  if ((!result) && (counter > 1)) {
     473    cout << Verbose(2) << "INFO: Degenerate triangle is ok, at least two, here " << counter << ", existing lines are used." << endl;
     474    result = true;
     475  }
     476  return result;
     477};
     478
     479
     480/** Sort function for the candidate list.
     481 */
     482bool SortCandidates(CandidateForTesselation* candidate1, CandidateForTesselation* candidate2)
     483{
     484  Vector BaseLineVector, OrthogonalVector, helper;
     485  if (candidate1->BaseLine != candidate2->BaseLine) {  // sanity check
     486    cout << Verbose(0) << "ERROR: sortCandidates was called for two different baselines: " << candidate1->BaseLine << " and " << candidate2->BaseLine << "." << endl;
     487    //return false;
     488    exit(1);
     489  }
     490  // create baseline vector
     491  BaseLineVector.CopyVector(candidate1->BaseLine->endpoints[1]->node->node);
     492  BaseLineVector.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
     493  BaseLineVector.Normalize();
     494
     495  // create normal in-plane vector to cope with acos() non-uniqueness on [0,2pi] (note that is pointing in the "right" direction already, hence ">0" test!)
     496  helper.CopyVector(candidate1->BaseLine->endpoints[0]->node->node);
     497  helper.SubtractVector(candidate1->point->node);
     498  OrthogonalVector.CopyVector(&helper);
     499  helper.VectorProduct(&BaseLineVector);
     500  OrthogonalVector.SubtractVector(&helper);
     501  OrthogonalVector.Normalize();
     502
     503  // calculate both angles and correct with in-plane vector
     504  helper.CopyVector(candidate1->point->node);
     505  helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
     506  double phi = BaseLineVector.Angle(&helper);
     507  if (OrthogonalVector.ScalarProduct(&helper) > 0) {
     508    phi = 2.*M_PI - phi;
     509  }
     510  helper.CopyVector(candidate2->point->node);
     511  helper.SubtractVector(candidate1->BaseLine->endpoints[0]->node->node);
     512  double psi = BaseLineVector.Angle(&helper);
     513  if (OrthogonalVector.ScalarProduct(&helper) > 0) {
     514    psi = 2.*M_PI - psi;
     515  }
     516
     517  cout << Verbose(2) << *candidate1->point << " has angle " << phi << endl;
     518  cout << Verbose(2) << *candidate2->point << " has angle " << psi << endl;
     519
     520  // return comparison
     521  return phi < psi;
     522};
     523
     524/**
     525 * Finds the point which is second closest to the provided one.
     526 *
     527 * @param Point to which to find the second closest other point
     528 * @param linked cell structure
     529 *
     530 * @return point which is second closest to the provided one
     531 */
     532TesselPoint* FindSecondClosestPoint(const Vector* Point, LinkedCell* LC)
     533{
     534  LinkedNodes *List = NULL;
     535  TesselPoint* closestPoint = NULL;
     536  TesselPoint* secondClosestPoint = NULL;
     537  double distance = 1e16;
     538  double secondDistance = 1e16;
     539  Vector helper;
     540  int N[NDIM], Nlower[NDIM], Nupper[NDIM];
     541
     542  LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
     543  for(int i=0;i<NDIM;i++) // store indices of this cell
     544    N[i] = LC->n[i];
     545  cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
     546
     547  LC->GetNeighbourBounds(Nlower, Nupper);
     548  //cout << endl;
     549  for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
     550    for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
     551      for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
     552        List = LC->GetCurrentCell();
     553        //cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
     554        if (List != NULL) {
     555          for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
     556            helper.CopyVector(Point);
     557            helper.SubtractVector((*Runner)->node);
     558            double currentNorm = helper. Norm();
     559            if (currentNorm < distance) {
     560              // remember second point
     561              secondDistance = distance;
     562              secondClosestPoint = closestPoint;
     563              // mark down new closest point
     564              distance = currentNorm;
     565              closestPoint = (*Runner);
     566              //cout << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *secondClosestPoint << "." << endl;
     567            }
     568          }
     569        } else {
     570          cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
     571            << LC->n[2] << " is invalid!" << endl;
     572        }
     573      }
     574
     575  return secondClosestPoint;
     576};
     577
     578/**
     579 * Finds the point which is closest to the provided one.
     580 *
     581 * @param Point to which to find the closest other point
     582 * @param SecondPoint the second closest other point on return, NULL if none found
     583 * @param linked cell structure
     584 *
     585 * @return point which is closest to the provided one, NULL if none found
     586 */
     587TesselPoint* FindClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC)
     588{
     589  LinkedNodes *List = NULL;
     590  TesselPoint* closestPoint = NULL;
     591  SecondPoint = NULL;
     592  double distance = 1e16;
     593  double secondDistance = 1e16;
     594  Vector helper;
     595  int N[NDIM], Nlower[NDIM], Nupper[NDIM];
     596
     597  LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly
     598  for(int i=0;i<NDIM;i++) // store indices of this cell
     599    N[i] = LC->n[i];
     600  cout << Verbose(2) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl;
     601
     602  LC->GetNeighbourBounds(Nlower, Nupper);
     603  //cout << endl;
     604  for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
     605    for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
     606      for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
     607        List = LC->GetCurrentCell();
     608        //cout << Verbose(3) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl;
     609        if (List != NULL) {
     610          for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
     611            helper.CopyVector(Point);
     612            helper.SubtractVector((*Runner)->node);
     613            double currentNorm = helper. Norm();
     614            if (currentNorm < distance) {
     615              secondDistance = distance;
     616              SecondPoint = closestPoint;
     617              distance = currentNorm;
     618              closestPoint = (*Runner);
     619              //cout << Verbose(2) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl;
     620            } else if (currentNorm < secondDistance) {
     621              secondDistance = currentNorm;
     622              SecondPoint = (*Runner);
     623              //cout << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl;
     624            }
     625          }
     626        } else {
     627          cerr << "ERROR: The current cell " << LC->n[0] << "," << LC->n[1] << ","
     628            << LC->n[2] << " is invalid!" << endl;
     629        }
     630      }
     631
     632  return closestPoint;
     633};
     634
     635/** Returns the closest point on \a *Base with respect to \a *OtherBase.
     636 * \param *out output stream for debugging
     637 * \param *Base reference line
     638 * \param *OtherBase other base line
     639 * \return Vector on reference line that has closest distance
     640 */
     641Vector * GetClosestPointBetweenLine(ofstream *out, class BoundaryLineSet *Base, class BoundaryLineSet *OtherBase)
     642{
     643  // construct the plane of the two baselines (i.e. take both their directional vectors)
     644  Vector Normal;
     645  Vector Baseline, OtherBaseline;
     646  Baseline.CopyVector(Base->endpoints[1]->node->node);
     647  Baseline.SubtractVector(Base->endpoints[0]->node->node);
     648  OtherBaseline.CopyVector(OtherBase->endpoints[1]->node->node);
     649  OtherBaseline.SubtractVector(OtherBase->endpoints[0]->node->node);
     650  Normal.CopyVector(&Baseline);
     651  Normal.VectorProduct(&OtherBaseline);
     652  Normal.Normalize();
     653  *out << Verbose(4) << "First direction is " << Baseline << ", second direction is " << OtherBaseline << ", normal of intersection plane is " << Normal << "." << endl;
     654
     655  // project one offset point of OtherBase onto this plane (and add plane offset vector)
     656  Vector NewOffset;
     657  NewOffset.CopyVector(OtherBase->endpoints[0]->node->node);
     658  NewOffset.SubtractVector(Base->endpoints[0]->node->node);
     659  NewOffset.ProjectOntoPlane(&Normal);
     660  NewOffset.AddVector(Base->endpoints[0]->node->node);
     661  Vector NewDirection;
     662  NewDirection.CopyVector(&NewOffset);
     663  NewDirection.AddVector(&OtherBaseline);
     664
     665  // calculate the intersection between this projected baseline and Base
     666  Vector *Intersection = new Vector;
     667  Intersection->GetIntersectionOfTwoLinesOnPlane(out, Base->endpoints[0]->node->node, Base->endpoints[1]->node->node, &NewOffset, &NewDirection, &Normal);
     668  Normal.CopyVector(Intersection);
     669  Normal.SubtractVector(Base->endpoints[0]->node->node);
     670  *out << Verbose(3) << "Found closest point on " << *Base << " at " << *Intersection << ", factor in line is " << fabs(Normal.ScalarProduct(&Baseline)/Baseline.NormSquared()) << "." << endl;
     671
     672  return Intersection;
     673};
     674
     675
     676/** Creates the objects in a VRML file.
     677 * \param *out output stream for debugging
     678 * \param *vrmlfile output stream for tecplot data
     679 * \param *Tess Tesselation structure with constructed triangles
     680 * \param *mol molecule structure with atom positions
     681 */
     682void WriteVrmlFile(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, PointCloud *cloud)
     683{
     684  TesselPoint *Walker = NULL;
     685  int i;
     686  Vector *center = cloud->GetCenter(out);
     687  if (vrmlfile != NULL) {
     688    //cout << Verbose(1) << "Writing Raster3D file ... ";
     689    *vrmlfile << "#VRML V2.0 utf8" << endl;
     690    *vrmlfile << "#Created by molecuilder" << endl;
     691    *vrmlfile << "#All atoms as spheres" << endl;
     692    cloud->GoToFirst();
     693    while (!cloud->IsEnd()) {
     694      Walker = cloud->GetPoint();
     695      *vrmlfile << "Sphere {" << endl << "  "; // 2 is sphere type
     696      for (i=0;i<NDIM;i++)
     697        *vrmlfile << Walker->node->x[i]-center->x[i] << " ";
     698      *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
     699      cloud->GoToNext();
     700    }
     701
     702    *vrmlfile << "# All tesselation triangles" << endl;
     703    for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
     704      *vrmlfile << "1" << endl << "  "; // 1 is triangle type
     705      for (i=0;i<3;i++) { // print each node
     706        for (int j=0;j<NDIM;j++)  // and for each node all NDIM coordinates
     707          *vrmlfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
     708        *vrmlfile << "\t";
     709      }
     710      *vrmlfile << "1. 0. 0." << endl;  // red as colour
     711      *vrmlfile << "18" << endl << "  0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
     712    }
     713  } else {
     714    cerr << "ERROR: Given vrmlfile is " << vrmlfile << "." << endl;
     715  }
     716  delete(center);
     717};
     718
     719/** Writes additionally the current sphere (i.e. the last triangle to file).
     720 * \param *out output stream for debugging
     721 * \param *rasterfile output stream for tecplot data
     722 * \param *Tess Tesselation structure with constructed triangles
     723 * \param *mol molecule structure with atom positions
     724 */
     725void IncludeSphereinRaster3D(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, PointCloud *cloud)
     726{
     727  Vector helper;
     728  // include the current position of the virtual sphere in the temporary raster3d file
     729  Vector *center = cloud->GetCenter(out);
     730  // make the circumsphere's center absolute again
     731  helper.CopyVector(Tess->LastTriangle->endpoints[0]->node->node);
     732  helper.AddVector(Tess->LastTriangle->endpoints[1]->node->node);
     733  helper.AddVector(Tess->LastTriangle->endpoints[2]->node->node);
     734  helper.Scale(1./3.);
     735  helper.SubtractVector(center);
     736  // and add to file plus translucency object
     737  *rasterfile << "# current virtual sphere\n";
     738  *rasterfile << "8\n  25.0    0.6     -1.0 -1.0 -1.0     0.2        0 0 0 0\n";
     739  *rasterfile << "2\n  " << helper.x[0] << " " << helper.x[1] << " " << helper.x[2] << "\t" << 5. << "\t1 0 0\n";
     740  *rasterfile << "9\n  terminating special property\n";
     741  delete(center);
     742};
     743
     744/** Creates the objects in a raster3d file (renderable with a header.r3d).
     745 * \param *out output stream for debugging
     746 * \param *rasterfile output stream for tecplot data
     747 * \param *Tess Tesselation structure with constructed triangles
     748 * \param *mol molecule structure with atom positions
     749 */
     750void WriteRaster3dFile(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, PointCloud *cloud)
     751{
     752  TesselPoint *Walker = NULL;
     753  int i;
     754  Vector *center = cloud->GetCenter(out);
     755  if (rasterfile != NULL) {
     756    //cout << Verbose(1) << "Writing Raster3D file ... ";
     757    *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl;
     758    *rasterfile << "@header.r3d" << endl;
     759    *rasterfile << "# All atoms as spheres" << endl;
     760    cloud->GoToFirst();
     761    while (!cloud->IsEnd()) {
     762      Walker = cloud->GetPoint();
     763      *rasterfile << "2" << endl << "  ";  // 2 is sphere type
     764      for (i=0;i<NDIM;i++)
     765        *rasterfile << Walker->node->x[i]-center->x[i] << " ";
     766      *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
     767      cloud->GoToNext();
     768    }
     769
     770    *rasterfile << "# All tesselation triangles" << endl;
     771    *rasterfile << "8\n  25. -1.   1. 1. 1.   0.0    0 0 0 2\n  SOLID     1.0 0.0 0.0\n  BACKFACE  0.3 0.3 1.0   0 0\n";
     772    for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
     773      *rasterfile << "1" << endl << "  ";  // 1 is triangle type
     774      for (i=0;i<3;i++) {  // print each node
     775        for (int j=0;j<NDIM;j++)  // and for each node all NDIM coordinates
     776          *rasterfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
     777        *rasterfile << "\t";
     778      }
     779      *rasterfile << "1. 0. 0." << endl;  // red as colour
     780      //*rasterfile << "18" << endl << "  0.5 0.5 0.5" << endl;  // 18 is transparency type for previous object
     781    }
     782    *rasterfile << "9\n#  terminating special property\n";
     783  } else {
     784    cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl;
     785  }
     786  IncludeSphereinRaster3D(out, rasterfile, Tess, cloud);
     787  delete(center);
     788};
     789
     790/** This function creates the tecplot file, displaying the tesselation of the hull.
     791 * \param *out output stream for debugging
     792 * \param *tecplot output stream for tecplot data
     793 * \param N arbitrary number to differentiate various zones in the tecplot format
     794 */
     795void WriteTecplotFile(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, PointCloud *cloud, int N)
     796{
     797  if ((tecplot != NULL) && (TesselStruct != NULL)) {
     798    // write header
     799    *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
     800    *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\" \"U\"" << endl;
     801    *tecplot << "ZONE T=\"" << N << "-";
     802    for (int i=0;i<3;i++)
     803      *tecplot << (i==0 ? "" : "_") << TesselStruct->LastTriangle->endpoints[i]->node->Name;
     804    *tecplot << "\", N=" << TesselStruct->PointsOnBoundary.size() << ", E=" << TesselStruct->TrianglesOnBoundary.size() << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
     805    int i=0;
     806    for (cloud->GoToFirst(); !cloud->IsEnd(); cloud->GoToNext(), i++);
     807    int *LookupList = new int[i];
     808    for (cloud->GoToFirst(), i=0; !cloud->IsEnd(); cloud->GoToNext(), i++)
     809      LookupList[i] = -1;
     810
     811    // print atom coordinates
     812    *out << Verbose(2) << "The following triangles were created:";
     813    int Counter = 1;
     814    TesselPoint *Walker = NULL;
     815    for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
     816      Walker = target->second->node;
     817      LookupList[Walker->nr] = Counter++;
     818      *tecplot << Walker->node->x[0] << " " << Walker->node->x[1] << " " << Walker->node->x[2] << " " << target->second->value << endl;
     819    }
     820    *tecplot << endl;
     821    // print connectivity
     822    for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
     823      *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
     824      *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
     825    }
     826    delete[] (LookupList);
     827    *out << endl;
     828  }
     829};
  • src/tesselationhelpers.hpp

    r91e7e4a r57066a  
    2525
    2626#include "defs.hpp"
     27#include "tesselation.hpp"
    2728#include "vector.hpp"
    2829
     
    3738bool existsIntersection(Vector point1, Vector point2, Vector point3, Vector point4);
    3839double CalculateVolumeofGeneralTetraeder(Vector *a, Vector *b, Vector *c, Vector *d);
     40double GetAngle(const Vector &point, const Vector &reference, const Vector OrthogonalVector);
     41
     42bool CheckLineCriteriaForDegeneratedTriangle(class BoundaryPointSet *nodes[3]);
     43bool SortCandidates(class CandidateForTesselation* candidate1, class CandidateForTesselation* candidate2);
     44TesselPoint* FindClosestPoint(const Vector* Point, TesselPoint *&SecondPoint, LinkedCell* LC);
     45TesselPoint* FindSecondClosestPoint(const Vector*, LinkedCell*);
     46Vector * GetClosestPointBetweenLine(ofstream *out, class BoundaryLineSet *Base, class BoundaryLineSet *OtherBase);
     47
     48void WriteTecplotFile(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, PointCloud *cloud, int N);
     49void WriteRaster3dFile(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, PointCloud *cloud);
     50void IncludeSphereinRaster3D(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, PointCloud *cloud);
     51void WriteVrmlFile(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, PointCloud *cloud);
    3952
    4053
Note: See TracChangeset for help on using the changeset viewer.