Ignore:
Timestamp:
Sep 28, 2009, 8:00:33 PM (16 years ago)
Author:
Frederik Heber <heber@…>
Children:
fca6e7
Parents:
bb56cf
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
File:
1 edited

Legend:

Unmodified
Added
Removed
  • molecuilder/src/tesselationhelpers.cpp

    rbb56cf r60cbe5  
    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};
Note: See TracChangeset for help on using the changeset viewer.