Forked from
gmsh / gmsh
12660 commits behind the upstream repository.
-
Emilie Marchandise authoredEmilie Marchandise authored
MVertex.cpp 12.67 KiB
// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <gmsh@geuz.org>.
#include <string.h>
#include <math.h>
#include "MVertex.h"
#include "GVertex.h"
#include "GEdge.h"
#include "GFace.h"
#include "GFaceCompound.h"
#include "GmshMessage.h"
#include "StringUtils.h"
int MVertex::_globalNum = 0;
double MVertexLessThanLexicographic::tolerance = 1.e-6;
bool MVertexLessThanLexicographic::operator()(const MVertex *v1, const MVertex *v2) const
{
if(v1->x() - v2->x() > tolerance) return true;
if(v1->x() - v2->x() < -tolerance) return false;
if(v1->y() - v2->y() > tolerance) return true;
if(v1->y() - v2->y() < -tolerance) return false;
if(v1->z() - v2->z() > tolerance) return true;
return false;
}
bool MVertexLessThanNum::operator()(const MVertex *v1, const MVertex *v2) const
{
if(v1->getNum() < v2->getNum()) return true;
return false;
}
double angle3Vertices(MVertex *p1, MVertex *p2, MVertex *p3)
{
SVector3 a(p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z());
SVector3 b(p3->x() - p2->x(), p3->y() - p2->y(), p3->z() - p2->z());
SVector3 c = crossprod(a, b);
double sinA = c.norm();
double cosA = dot(a, b);
return atan2 (sinA, cosA);
}
MVertex::MVertex(double x, double y, double z, GEntity *ge, int num)
: _visible(1), _order(1), _x(x), _y(y), _z(z), _ge(ge)
{
#pragma omp critical
{
if(num){
_num = num;
_globalNum = std::max(_globalNum, _num);
}
else{
_num = ++_globalNum;
}
_index = num;
}
}
void MVertex::forceNum(int num)
{
#pragma omp critical
{
_num = num;
_globalNum = std::max(_globalNum, _num);
}
}
void MVertex::writeMSH(FILE *fp, bool binary, bool saveParametric, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
int myDim = 0, myTag = 0;
if(saveParametric){
if(onWhat()){
myDim = onWhat()->dim();
myTag = onWhat()->tag();
}
else
saveParametric = false;
}
if(!binary){
if(!saveParametric)
fprintf(fp, "%d %.16g %.16g %.16g\n", _index, x() * scalingFactor,
y() * scalingFactor, z() * scalingFactor);
else
fprintf(fp, "%d %.16g %.16g %.16g %d %d", _index, x() * scalingFactor,
y() * scalingFactor, z() * scalingFactor, myDim, myTag);
}
else{
fwrite(&_index, sizeof(int), 1, fp);
double data[3] = {x() * scalingFactor, y() * scalingFactor, z() * scalingFactor};
fwrite(data, sizeof(double), 3, fp);
if(saveParametric){
fwrite(&myDim, sizeof(int), 1, fp);
fwrite(&myTag, sizeof(int), 1, fp);
}
}
if(saveParametric){
if(myDim == 1){
double _u;
getParameter(0, _u);
if(!binary)
fprintf(fp, " %.16g\n", _u);
else
fwrite(&_u, sizeof(double), 1, fp);
}
else if (myDim == 2){
double _u, _v;
getParameter(0, _u);
getParameter(1, _v);
if(!binary)
fprintf(fp, " %.16g %.16g\n", _u, _v);
else{
fwrite(&_u, sizeof(double), 1, fp);
fwrite(&_v, sizeof(double), 1, fp);
}
}
else
if(!binary)
fprintf(fp, "\n");
}
}
void MVertex::writePLY2(FILE *fp)
{
if(_index < 0) return; // negative index vertices are never saved
fprintf(fp, "%.16g %.16g %.16g\n", x(), y(), z());
}
void MVertex::writeVRML(FILE *fp, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
fprintf(fp, "%.16g %.16g %.16g,\n",
x() * scalingFactor, y() * scalingFactor, z() * scalingFactor);
}
void MVertex::writeUNV(FILE *fp, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
int coord_sys = 1;
int displacement_coord_sys = 1;
int color = 11;
fprintf(fp, "%10d%10d%10d%10d\n", _index, coord_sys, displacement_coord_sys, color);
// hack to print the numbers with "D+XX" exponents
char tmp[128];
sprintf(tmp, "%25.16E%25.16E%25.16E\n", x() * scalingFactor,
y() * scalingFactor, z() * scalingFactor);
for(unsigned int i = 0; i < strlen(tmp); i++) if(tmp[i] == 'E') tmp[i] = 'D';
fprintf(fp, "%s", tmp);
}
void MVertex::writeVTK(FILE *fp, bool binary, double scalingFactor, bool bigEndian)
{
if(_index < 0) return; // negative index vertices are never saved
if(binary){
double data[3] = {x() * scalingFactor, y() * scalingFactor, z() * scalingFactor};
// VTK always expects big endian binary data
if(!bigEndian) SwapBytes((char*)data, sizeof(double), 3);
fwrite(data, sizeof(double), 3, fp);
}
else{
fprintf(fp, "%.16g %.16g %.16g\n",
x() * scalingFactor, y() * scalingFactor, z() * scalingFactor);
}
}
void MVertex::writeMESH(FILE *fp, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
fprintf(fp, " %20.14G %20.14G %20.14G %d\n",
x() * scalingFactor, y() * scalingFactor, z() * scalingFactor,
_ge ? _ge->tag() : 0);
}
static void double_to_char8(double val, char *str)
{
if(val >= 1.e6)
sprintf(str, "%.2E", val);
else if(val >= 1.e-3)
sprintf(str, "%f", val);
else if(val >= 0)
sprintf(str, "%.2E", val);
else if(val >= -1.e-3)
sprintf(str, "%.1E", val);
else if(val >= -1.e6)
sprintf(str, "%f", val);
else
sprintf(str, "%.1E", val);
#if defined(WIN32)
// Windows uses 3 digits in the exponent (which apparently does not
// conform with ANSI C): remove the extra 0
if(strlen(str) == 9 && (str[4] == 'E' || str[5] == 'E')){
str[6] = str[7];
str[7] = str[8];
}
#endif
str[8] = '\0';
}
void MVertex::writeBDF(FILE *fp, int format, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
char xs[17], ys[17], zs[17];
double x1 = x() * scalingFactor;
double y1 = y() * scalingFactor;
double z1 = z() * scalingFactor;
if(format == 0){
// free field format (max 8 char per field, comma separated, 10 per line)
double_to_char8(x1, xs); double_to_char8(y1, ys); double_to_char8(z1, zs);
fprintf(fp, "GRID,%d,%d,%s,%s,%s\n", _index, 0, xs, ys, zs);
}
else if(format == 1){
// small field format (8 char par field, 10 per line)
double_to_char8(x1, xs); double_to_char8(y1, ys); double_to_char8(z1, zs);
fprintf(fp, "GRID %-8d%-8d%-8s%-8s%-8s\n", _index, 0, xs, ys, zs);
}
else{
// large field format (8 char first/last field, 16 char middle, 6 per line)
fprintf(fp, "GRID* %-16d%-16d%-16.9G%-16.9G*N%-6d\n", _index, 0, x1, y1, _index);
fprintf(fp, "*N%-6d%-16.9G\n", _index, z1);
}
}
void MVertex::writeINP(FILE *fp, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
fprintf(fp, "%d, %.16g, %.16g, %.16g\n", _index, x() * scalingFactor,
y() * scalingFactor, z() * scalingFactor);
}
void MVertex::writeDIFF(FILE *fp, bool binary, double scalingFactor)
{
if(_index < 0) return; // negative index vertices are never saved
fprintf(fp, " %d ( %25.16E , %25.16E , %25.16E )",
_index, x() * scalingFactor, y() * scalingFactor, z() * scalingFactor);
}
std::set<MVertex*, MVertexLessThanLexicographic>::iterator
MVertex::linearSearch(std::set<MVertex*, MVertexLessThanLexicographic> &pos)
{
for(std::set<MVertex*, MVertexLessThanLexicographic>::iterator it = pos.begin();
it != pos.end(); ++it)
if(distance(*it) < MVertexLessThanLexicographic::tolerance) return it;
return pos.end();
}
static void getAllParameters(MVertex *v, GFace *gf, std::vector<SPoint2> ¶ms)
{
params.clear();
if (gf->geomType() == GEntity::CompoundSurface &&
v->onWhat()->dim() < 2){
GFaceCompound *gfc = (GFaceCompound*) gf;
params.push_back(gfc->getCoordinates(v));
return;
}
if(v->onWhat()->dim() == 0){
GVertex *gv = (GVertex*)v->onWhat();
std::list<GEdge*> ed = gv->edges();
bool seam = false;
for(std::list<GEdge*>::iterator it = ed.begin(); it != ed.end(); it++){
if((*it)->isSeam(gf)) {
Range<double> range = (*it)->parBounds(0);
if (gv == (*it)->getBeginVertex()){
params.push_back((*it)->reparamOnFace(gf, range.low(),-1));
params.push_back((*it)->reparamOnFace(gf, range.low(), 1));
}
else if (gv == (*it)->getEndVertex()){
params.push_back((*it)->reparamOnFace(gf, range.high(),-1));
params.push_back((*it)->reparamOnFace(gf, range.high(), 1));
}
else{
Msg::Warning("Strange!");
}
seam = true;
}
}
if (!seam)
params.push_back(gv->reparamOnFace(gf, 1));
}
else if(v->onWhat()->dim() == 1){
GEdge *ge = (GEdge*)v->onWhat();
if(!ge->haveParametrization()) return;
double UU;
v->getParameter(0, UU);
if (UU == 0.0)
UU = ge->parFromPoint(v->point());
params.push_back(ge->reparamOnFace(gf, UU, 1));
if(ge->isSeam(gf))
params.push_back(ge->reparamOnFace(gf, UU, -1));
}
else{
double UU, VV;
if(v->onWhat() == gf && v->getParameter(0, UU) && v->getParameter(1, VV))
params.push_back(SPoint2(UU, VV));
}
}
bool reparamMeshEdgeOnFace(MVertex *v1, MVertex *v2, GFace *gf,
SPoint2 ¶m1, SPoint2 ¶m2)
{
std::vector<SPoint2> p1, p2;
getAllParameters(v1, gf, p1);
getAllParameters(v2, gf, p2);
if (p1.size() == 1 && p2.size() == 1){
param1 = p1[0];
param2 = p2[0];
return true;
}
else if (p1.size() == 1 && p2.size() == 2){
double d1 =
(p1[0].x() - p2[0].x()) * (p1[0].x() - p2[0].x()) +
(p1[0].y() - p2[0].y()) * (p1[0].y() - p2[0].y());
double d2 =
(p1[0].x() - p2[1].x()) * (p1[0].x() - p2[1].x()) +
(p1[0].y() - p2[1].y()) * (p1[0].y() - p2[1].y());
param1 = p1[0];
param2 = d2 < d1 ? p2[1] : p2[0];
return true;
}
else if (p2.size() == 1 && p1.size() == 2){
double d1 =
(p2[0].x() - p1[0].x()) * (p2[0].x() - p1[0].x()) +
(p2[0].y() - p1[0].y()) * (p2[0].y() - p1[0].y());
double d2 =
(p2[0].x() - p1[1].x()) * (p2[0].x() - p1[1].x()) +
(p2[0].y() - p1[1].y()) * (p2[0].y() - p1[1].y());
param1 = d2 < d1 ? p1[1] : p1[0];
param2 = p2[0];
return true;
}
else if(p1.size() > 1 && p2.size() > 1){
param1 = p1[0];
param2 = p2[0];
printf("NO WAY : TWO VERTICES ON THE SEAM, CANNOT CHOOSE\n");
// shout, both vertices are on seams
return false;
}
else{
// brute force!
param1 = gf->parFromPoint(SPoint3(v1->x(), v1->y(), v1->z()));
param2 = gf->parFromPoint(SPoint3(v2->x(), v2->y(), v2->z()));
return true;
}
}
bool reparamMeshVertexOnFace(const MVertex *v, const GFace *gf, SPoint2 ¶m,
bool onSurface)
{
if (gf->geomType() == GEntity::CompoundSurface &&
v->onWhat()->dim() < 2){
GFaceCompound *gfc = (GFaceCompound*) gf;
param = gfc->getCoordinates(const_cast<MVertex*>(v));
return true;
}
if(v->onWhat()->geomType() == GEntity::DiscreteCurve ||
v->onWhat()->geomType() == GEntity::BoundaryLayerCurve){
param = gf->parFromPoint(SPoint3(v->x(), v->y(), v->z()), onSurface);
return true;
}
if(v->onWhat()->dim() == 0){
GVertex *gv = (GVertex*)v->onWhat();
// hack for bug in periodic curves
if (gv->getNativeType() == GEntity::GmshModel && gf->geomType() == GEntity::Plane)
param = gf->parFromPoint(SPoint3(v->x(), v->y(), v->z()), onSurface);
else
param = gv->reparamOnFace(gf, 1);
// shout, we could be on a seam
std::list<GEdge*> ed = gv->edges();
for(std::list<GEdge*>::iterator it = ed.begin(); it != ed.end(); it++)
if((*it)->isSeam(gf)) return false;
}
else if(v->onWhat()->dim() == 1){
GEdge *ge = (GEdge*)v->onWhat();
double t;
v->getParameter(0, t);
param = ge->reparamOnFace(gf, t, 1);
// shout, we are on a seam
if(ge->isSeam(gf))
return false;
}
else{
double uu, vv;
if(v->onWhat() == gf && v->getParameter(0, uu) && v->getParameter(1, vv)){
// printf("%d face %d pos %g %g\n",v->getNum(),gf->tag(),uu,vv);
param = SPoint2(uu, vv);
}
else {
// brute force!
param = gf->parFromPoint(SPoint3(v->x(), v->y(), v->z()), onSurface);
}
}
return true;
}
bool reparamMeshVertexOnEdge(const MVertex *v, const GEdge *ge, double ¶m)
{
param = 1.e6;
Range<double> bounds = ge->parBounds(0);
bool ok = true;
if(ge->getBeginVertex() && ge->getBeginVertex()->mesh_vertices[0] == v)
param = bounds.low();
else if(ge->getEndVertex() && ge->getEndVertex()->mesh_vertices[0] == v)
param = bounds.high();
else
ok = v->getParameter(0, param);
if(!ok || param == 1.e6)
param = ge->parFromPoint(SPoint3(v->x(), v->y(), v->z()));
if(param < 1.e6) return true;
return false;
}