/***********************************************************************
*
* ELMER, A Computational Fluid Dynamics Program.
*
* Copyright 1st April 1995 - , Center for Scientific Computing,
* Finland.
*
* All rights reserved. No part of this program may be used,
* reproduced or transmitted in any form or by any means
* without the written permission of CSC.
*
* Address: Center for Scientific Computing
* Tietotie 6, P.O. BOX 405
* 02101 Espoo, Finland
* Tel. +358 0 457 2001
* Telefax: +358 0 457 2302
* EMail: Jari.Jarvinen@csc.fi
************************************************************************/
/***********************************************************************
Program: ELMER Front
Module: ecif_geometry.cpp
Language: C++
Date: 01.10.98
Version: 1.00
Author(s): Martti Verho
Revisions:
Abstract: Implementation
************************************************************************/
#include "ecif_def_stl.h"
#include "ecif_boundbox.h"
#include "ecif_bodyElement.h"
#include "ecif_bodyElement1D.h"
#include "ecif_control.h"
#include "ecif_geometry.h"
#include "ecif_model.h"
#include "ecif_nurbs.h"
#include "ecif_renderer.h"
#include "ecif_userinterface.h"
// Typedefs for safer calling
typedef int (Callbackp dllCircleFunc)(enum egf_FuncType ft, int argc, double* argv,
egf_Point3* start, egf_Point3* end,
int& nof_circles, egf_Circle*& circles);
typedef int (Callbackp dllPolyLineFunc)(enum egf_FuncType ft, int argc, double* argv,
egf_Point3* start, egf_Point3* end,
int& nof_polylines, egf_PolyLine*& polylines);
// Static class variables
//
Model* Geometry::model = NULL;
ecif_geometryType GcCircle::type = ECIF_CIRCLE;
ecif_geometryType GcLine::type = ECIF_LINE;
ecif_geometryType GcPlane::type = ECIF_LINE;
ecif_geometryType GcPoint::type = ECIF_NODIM;
ecif_geometryType GcPolyLine::type = ECIF_POLYLINE;
ecif_geometryType GcNurbsCurve::type = ECIF_NURBS;
ecif_geometryType GcNurbsSurface::type = ECIF_NURBS;
//extern const float colorValues[][4];
RayHit::RayHit() {
count = 0;
min_value = 1.0e+100;
}
RayHit::~RayHit() {
Point3List::iterator itr;
for (itr = points.begin(); itr != points.end(); itr++) {
delete *itr;
}
points.clear();
}
//***************************
//*****Geometry methods *****
//***************************
Geometry::Geometry() {
boundbox = NULL;
geometryOk = true;
}
Geometry::~Geometry()
{
delete boundbox;
}
void
Geometry::calcLinearizingPoints(int& nof_points_u, int& nof_points_v, GcPoint**& points, double delta_u, double delta_v)
{
nof_points_u = 0;
nof_points_v = 0;
points = NULL;
}
// Just cover function to call a more specific form
void
Geometry::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction)
{
draw(renderer, dmode, dstate);
}
// Just cover function to call a more specific form
void
Geometry::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
draw(renderer, dmode, dstate, direction);
}
// Just cover function to call a more specific form
void
Geometry::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id, bool is_first_loop)
{
draw(renderer, dmode, dstate, direction, elem_id);
}
// Just cover function to call a more specific form
void
Geometry::draw(int gmtr_index, Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction)
{
if ( gmtr_index < 0 ) return;
if ( isMultiGeometry() ) {
draw(gmtr_index, renderer, dmode, dstate);
} else {
draw(renderer, dmode, dstate, direction);
}
}
// Just cover function to call a more specific form
void
Geometry::draw(int gmtr_index, Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
if ( gmtr_index < 0 ) return;
if ( isMultiGeometry() ) {
draw(gmtr_index, renderer, dmode, dstate, direction);
} else {
draw(renderer, dmode, dstate, direction, elem_id);
}
}
// Just cover function to call a more specific form
void
Geometry::draw(int gmtr_index, Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id, bool is_first_loop)
{
if ( gmtr_index < 0 ) return;
if ( isMultiGeometry() ) {
draw(gmtr_index, renderer, dmode, dstate, direction, elem_id);
} else {
draw(renderer, dmode, dstate, direction, elem_id, is_first_loop);
}
}
void
Geometry::getBoundaryPoints(int& count, BoundaryPoint**& points)
{
points = NULL;
count = 0;
}
void
Geometry::getDiscretizationData(int& nof_components, linDeltaType*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = 0;
types = NULL;
valuesU = NULL;
valuesV = NULL;
useFixedN = NULL;
}
// Finds 'nice' positions for the label point
void
Geometry::getLabelPoint(Point3& point)
{
GcPoint* p = param2Point(0.5, 0.5);
if (p != NULL) {
point[0] = p->Pos(X);
point[1] = p->Pos(Y);
point[2] = p->Pos(Z);
}
else {
point[0] = point[1] = point[2] = NSVD;
}
}
void
Geometry::getMifTags(int& nof_tags, int*& tags)
{
nof_tags = 0;
tags = NULL;
}
//**************************************************************************
// Geometry1D methods
//**************************************************************************
Geometry1D::Geometry1D()
{
}
Geometry1D::~Geometry1D()
{
}
//****************************
//***** GcPoint methods *****
//****************************
GcPoint::GcPoint()
{
posit[X] = 0;
posit[Y] = 0;
posit[Z] = 0;
}
GcPoint
GcPoint::average(GcPoint &p2, GcPoint&p3)
{
GcPoint res;
for (char i = 0; i < MAX_DIMENSION; i++)
res.posit[i] = (posit[i] + p2.posit[i] + p3.posit[i]) / 3;
return res;
}
void
GcPoint::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate)
{
renderer->drawPoint(dmode, dstate, &posit);
}
// Searching for space: if GcPoint is outside space extend the space
void
GcPoint::find_space(GcPoint &pmin, GcPoint &pmax)
{
for (char i = 0; i < MAX_DIMENSION; i++) {
if (pmin.posit[i] > posit[i])
pmin.posit[i] = posit[i];
if (pmax.posit[i] < posit[i])
pmax.posit[i] = posit[i];
}
}
// Finds 'nice' positions for the label point
void
GcPoint::getLabelPoint(Point3& point)
{
point[0] = posit[0];
point[1] = posit[1];
point[2] = posit[2];
}
int
GcPoint::hashKey()
{
return int(posit[X]);
}
bool
GcPoint::isBetween(GcPoint* p1, GcPoint* p2)
{
GcPoint tmp1 = *this - *p1;
GcPoint tmp2 = *p2 - *this;
GcPoint tmp = *p2 - *p1;
return ((tmp1 < tmp) && (tmp2 < tmp));
}
bool
GcPoint::isParallel(GcPoint* other_vector)
{
//We check if cross product is zero-vector.
GcPoint* ov = other_vector;
double tmp1 = fabs(posit[Y] * ov->posit[Z] - posit[Z] * ov->posit[Y]);
double tmp2 = fabs(posit[X] * ov->posit[Z] - posit[Z] * ov->posit[X]);
double tmp3 = fabs(posit[X] * ov->posit[Y] - posit[Y] * ov->posit[X]);
return ((tmp1 < POINT_EPSILON) && (tmp2 < POINT_EPSILON) && (tmp3 < POINT_EPSILON));
}
void
GcPoint::normalize(double norm[3], double shift[3])
{
for (int i = 0; i < 3 ; i++) {
if ( norm[i] > 0 )
posit[i] = (posit[i] + shift[i]) / norm[i];
}
}
void
GcPoint::de_normalize(double norm[3], double shift[3])
{
posit[0] = (posit[0] * norm[0]) - shift[0];
posit[1] = (posit[1] * norm[1]) - shift[1];
posit[2] = (posit[2] * norm[2]) - shift[2];
}
ostream&
GcPoint::output_emf(ostream& out, short indent_size, short indent_level)
{
LibFront::output_vector(out, indent_size, indent_level, "Point", NULL, 3, posit, false);
return out;
}
// *** System operators
bool
GcPoint::operator==(const GcPoint& p2)
{
GcPoint hlp;
double tmp;
hlp = *this - p2;
if ((hlp.posit[X] < POINT_EPSILON) && (hlp.posit[X] > -POINT_EPSILON) &&
(hlp.posit[Y] < POINT_EPSILON) && (hlp.posit[Y] > -POINT_EPSILON) &&
(hlp.posit[Z] < POINT_EPSILON) && (hlp.posit[Z] > -POINT_EPSILON))
return true;
else
return false;
tmp = sqrt(hlp.posit[X] * hlp.posit[X] + hlp.posit[Y] * hlp.posit[Y]
+ hlp.posit[Z] * hlp.posit[Z]);
if (tmp < POINT_EPSILON && tmp > -POINT_EPSILON)
return true;
else
return false;
}
ostream &
operator<<(ostream& stream, const GcPoint& p)
{
stream << p.posit[X] << " ";
stream << p.posit[Y] << " ";
stream << p.posit[Z];
return stream;
}
// *** Arithmetic operators
GcPoint
operator+(const GcPoint& p1, const GcPoint& p2)
{
double p[MAX_DIMENSION];
for (short i = 0; i < MAX_DIMENSION; i++)
p[i] = p1.posit[i] + p2.posit[i];
return GcPoint(p[X], p[Y], p[Z]);
}
GcPoint
operator-(const GcPoint& p1, const GcPoint& p2)
{
double p[MAX_DIMENSION];
for (short i = 0; i < MAX_DIMENSION; i++)
p[i] = p1.posit[i] - p2.posit[i];
return GcPoint(p[X], p[Y], p[Z]);
}
GcPoint
operator*(int num, const GcPoint& p)
{
double tmp[MAX_DIMENSION];
for (short i = 0; i < MAX_DIMENSION; i++)
tmp[i] = num * p.posit[i];
return GcPoint(tmp[X], tmp[Y], tmp[Z]);
}
GcPoint
operator/(const GcPoint& p, int num)
{
double tmp[MAX_DIMENSION];
for (short i = 0; i < MAX_DIMENSION; i++)
if ( num != 0 )
tmp[i] = p.posit[i] / num;
return GcPoint(tmp[X], tmp[Y], tmp[Z]);
}
// *** Relational operators
bool
operator==(const GcPoint &p1, const GcPoint &p2)
{
GcPoint hlp;
hlp = p1 - p2;
if ((hlp.posit[X] < POINT_EPSILON) && (hlp.posit[X] > -POINT_EPSILON) &&
(hlp.posit[Y] < POINT_EPSILON) && (hlp.posit[Y] > -POINT_EPSILON) &&
(hlp.posit[Z] < POINT_EPSILON) && (hlp.posit[Z] > -POINT_EPSILON))
return true;
else
return false;
}
bool
operator!=(const GcPoint& p1, const GcPoint& p2)
{
if (p1 == p2)
return true;
else
return false;
}
bool
operator<(const GcPoint& p1, const GcPoint& p2)
{
if ((p1.Pos(X) < p2.Pos(X)) && (p1.Pos(Y) < p2.Pos(Y)) &&
(p1.Pos(Z) < p2.Pos(Z)))
return true;
else
return false;
}
bool
operator>(const GcPoint& p1, const GcPoint& p2)
{
if ((p1.posit[X] > p2.posit[X]) && (p1.posit[Y] > p2.posit[Y]) &&
(p1.posit[Z] > p2.posit[Z]))
return true;
else
return false;
}
bool
operator<=(const GcPoint& p1, const GcPoint& p2)
{
if ((p1.posit[X] <= p2.posit[X]) && (p1.posit[Y] <= p2.posit[Y]) &&
(p1.posit[Z] <= p2.posit[Z]))
return 1;
else
return 0;
}
bool
operator>=(const GcPoint& p1, const GcPoint& p2)
{
if ((p1.posit[X] >= p2.posit[X]) && (p1.posit[Y] >= p2.posit[Y]) &&
(p1.posit[Z] >= p2.posit[Z]))
return 1;
else
return 0;
}
//*end GcPoint methods
//******************************
// Methods for TransMatrix class
TransfMatrix::TransfMatrix()
{
AA = 1; EE = 1; II = 1;
BB = 0; CC = 0; DD = 0; FF = 0; GG = 0; HH = 0; JJ = 0; KK = 0; LL = 0;
}
TransfMatrix::TransfMatrix(double a, double b, double c, double d, double e, double f,
double g, double h, double i, double j, double k, double l)
{
AA = a; BB = b; CC = c; DD = d; EE = e; FF = f;
GG = g; HH = h; II = i; JJ = j; KK = k; LL = l;
}
TransfMatrix::TransfMatrix(TransfMatrix &m)
{
*this = m;
}
void
TransfMatrix::transform(GcPoint& oldp, GcPoint& newp)
{
double tmpx = AA * oldp.Pos(X) + DD * oldp.Pos(Y) + GG * oldp.Pos(Z) + JJ;
double tmpy = BB * oldp.Pos(X) + EE * oldp.Pos(Y) + HH * oldp.Pos(Z) + KK;
double tmpz = CC * oldp.Pos(X) + FF * oldp.Pos(Y) + II * oldp.Pos(Z) + LL;
newp = GcPoint(tmpx, tmpy, tmpz);
}
TransfMatrix &
TransfMatrix::operator=(const TransfMatrix& m)
{
AA = m.AA; BB = m.BB; CC = m.CC;
DD = m.DD; EE = m.EE; FF = m.FF;
GG = m.GG; HH = m.HH; II = m.II;
JJ = m.JJ; KK = m.KK; LL = m.LL;
return *this;
}
//**************************************************************************
// Geometry2D methods
//**************************************************************************
Geometry2D::Geometry2D()
{
nofBoundaryPoints = 0;
boundaryPoints = NULL;
}
Geometry2D::~Geometry2D()
{
}
// Linearize geometry and store points in boundaryPoints array
//
void
Geometry2D::calcBoundaryPoints()
{
int i;
for (i = 0; i < nofBoundaryPoints; i++) {
delete boundaryPoints[i];
}
delete[] boundaryPoints;
nofBoundaryPoints = 0;
boundaryPoints = NULL;
int nof_points;
GcPoint** points;
double delta = getParamDeltaU();
calcLinearizingPoints(nof_points, points, delta);
model->updateMinimumEdgeSize(nof_points, points);
if (nof_points == 0) return;
boundaryPoints = new BoundaryPoint*[nof_points];
for (i = 0; i < nof_points; i++) {
BoundaryPoint* bp = new BoundaryPoint;
boundaryPoints[i] = bp;
// Check if bp is an existing vertex!
//BodyElement* v = model->getVertex(points[i]);
BodyElement* v = model->findVertex(points[i]);
if ( v != NULL ) {
bp->tag = v->Tag();
bp->vertexTag = v->Tag();
}
//bp->boundaryTag = boundary_tag;
bp->point = points[i];
}
// Handle possibly closed geometry
// -------------------------------
//-Copy start points to end point if U-closed
//
if ( isClosedU() ) {
boundaryPoints[nof_points - 1]->copy(*boundaryPoints[0]);
boundaryPoints[nof_points - 1]->activeInMeshing = false;
}
nofBoundaryPoints = nof_points;
// NOTE: Delete only array, not the points!!!
delete[] points;
}
void
Geometry2D::calcLinearizingPoints(int& nof_points, GcPoint**& points, double delta_u)
{
nof_points = 0;
points = NULL;
}
void
Geometry2D::calcLinearizingPoints(int& nof_points_u, int& nof_points_v, GcPoint**& points, double delta_u, double delta_v)
{
nof_points_u = 0;
nof_points_v = 0;
points = NULL;
calcLinearizingPoints(nof_points_u, points, delta_u);
}
void
Geometry2D::getBoundaryPoints(int& count, BoundaryPoint**& points)
{
points = NULL;
count = nofBoundaryPoints;
if ( count > 0 ) {
points = new BoundaryPoint*[count];
for (int i = 0; i < count; i++) {
points[i] = boundaryPoints[i];
}
}
}
void
Geometry2D::getDiscretizationData(int nof_components, char*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = 0;
types = NULL;
valuesU = NULL;
valuesV = NULL;
useFixedN = NULL;
}
void
Geometry2D::getMifTags(int& nof_tags, int*& tags)
{
nof_tags = 1;
tags = new int[1];
tags[0] = mifTag;
}
// Output boundary point tags (for Elmer Mesh input file)
//
ostream&
Geometry2D::outputBoundaryPointTags(ostream& out, int indent_size)
{
int max_per_line = 20;
//--Normal vertices
if ( nofBoundaryPoints == 0 ) {
for (int i = 0; i < nofVertices; i++) {
out << vertexTags[i] << " ";
}
//--Boundary points
} else {
int counter = 0;
BoundaryPoint* bp;
for (int i = 0; i < nofBoundaryPoints; i++) {
if ( isClosedU() && i == nofBoundaryPoints - 1 ) {
bp = boundaryPoints[0];
} else {
bp = boundaryPoints[i];
}
if ( bp != NULL ) {
out << bp->tag << " ";
counter++;
}
// Continue from next line
if ( counter >= max_per_line ) {
out << endl;
indent(out, indent_size);
counter = 0;
}
}
}
return out;
}
// Output boundary points for Elmer Mesh input file (mif-file)
//
ostream&
Geometry2D::output_mif(ostream& out, const char* hdr, bool useFxdMeshN)
{
int nof_points = 0;
//--Find nof nodes (verices or linearizing points)
//
if ( nofBoundaryPoints > 0 ) {
nof_points = nofBoundaryPoints;
} else {
nof_points = nofVertices;
}
// Print positions before and after printing fixed data
// (for getting the indent size for ids)
int pos1, pos2;
pos1 = out.tellp();
//---Mif-tag and boundary tag
//
out << "EdgeId: " << mifTag << " " << hdr;
// If fixed discretation
if ( useFxdMeshN && this->useFixedMeshN() ) {
out << " N: " << nof_points - 1;
}
//---Nof points and point (vertex or bpoint) tags
//
out << " " << nof_points << " ";
pos2 = out.tellp();
outputBoundaryPointTags(out, pos2 - pos1);
out << endl;
return out;
}
//****************************
//***** GcCircle methods *****
//****************************
// Constructor (for egf-files)
//
GcCircle::GcCircle(ecif_ElementComponent_X& tx, IdList& vertex_tags)
{
Point3** points = NULL;
nofVertices = tx.nof_vertices;
vertexTags = NULL;
if ( nofVertices > 0 ) {
points = new Point3*[nofVertices];
vertexTags = new int[nofVertices];
for (int i = 0; i < nofVertices; i++) {
BodyElement* v = model->getVertexByTag(tx.vertex_tags[i]);
vertex_tags.push_back(v->Tag());
vertexTags[i] = v->Tag();
points[i] = ((GcPoint*)v->getGeometry())->getPoint();
}
}
if ( !create(nofVertices, points, tx.geometry.edge, tx.lin_delta_type, tx.lin_delta[0]) ){
geometryOk = false;
return;
}
delete[] points;
data.useFixedMeshN = (bool)tx.use_fixed_mesh_n;
init();
copyMatcValueTable(tx.matcTable, data.matcTable);
copyMatcValueTable(tx.geometry.edge->matcTable, data.matcTable);
}
// Constructor
// NOTE: no vertices
//
GcCircle::GcCircle(Point3& center ,Point3& start, Point3& stop, bool do_linearize)
{
nofVertices = 0;
vertexTags = NULL;
Point3** points = new Point3*[2];
points[0] = &start;
points[1] = &stop;
ecif_EdgeGeometry_X* param = new ecif_EdgeGeometry_X;
init_trx_data(*param);
param->location = new Point3[1];
param->location[0][0] = center[0];
param->location[0][1] = center[1];
param->location[0][2] = center[2];
if ( !create(2, points, param, LIN_DELTA_NONE, -1.0, do_linearize) ) {
geometryOk = false;
}
delete[] points;
if (!geometryOk) return;
init(do_linearize);
reset_trx_data(*param);
delete param;
}
// Constructor
// NOTE: no vertices
//
GcCircle::GcCircle(int nof_points, Point3** points, ecif_EdgeGeometry_X* params, bool do_linearize)
{
int i;
nofVertices = 0;
vertexTags = NULL;
if ( !create(nof_points, points, params, LIN_DELTA_NONE, -1.0, do_linearize) ) {
geometryOk = false;
}
if (!geometryOk) return;
init(do_linearize);
}
// Constructor
//
GcCircle::GcCircle(BodyElement* vertex1, BodyElement* vertex2, ecif_EdgeGeometry_X* edge, bool do_linearize)
{
if ( vertex1 == vertex2 ) {
nofVertices = 1;
} else {
nofVertices = 2;
}
vertexTags = new int[2];
vertexTags[0] = vertex1->Tag();
vertexTags[1] = vertex2->Tag();
Point3** points = new Point3*[2];
points[0] = ((GcPoint*)vertex1->getGeometry())->getPoint();
points[1] = ((GcPoint*)vertex2->getGeometry())->getPoint();
if ( !create(nofVertices, points, edge, LIN_DELTA_NONE, -1.0, do_linearize) ) {
geometryOk = false;
}
delete[] points;
if (!geometryOk) return;
init(do_linearize);
}
// Create circle
bool
GcCircle::create(int nof_points, Point3** points, ecif_EdgeGeometry_X* params,
enum linDeltaType lin_delta_type, double lin_delta, bool do_linearize)
{
bool center_given = false;
bool radius_given = false;
Point3 p1, p2;
// Pick parameters
// ---------------
//--Circle arc
if ( nof_points == 2 ) {
data.start = new GcPoint(points[0]);
data.end = new GcPoint(points[1]);
data.start->getPoint(p1);
data.end->getPoint(p2);
if ( isZero(dist3(p1, p2)) ) {
data.isClosed = true;
} else {
data.isClosed = false;
}
//--Full circle
} else {
data.isClosed = true;
if ( params->start != NULL ) {
data.start = new GcPoint(params->start);
}
if ( params->end != NULL ) {
data.end = new GcPoint(params->end);
}
data.start_u = 0.0;
data.end_u = TWO_PI;
}
// If center given
if (params->location != NULL) {
data.centerGiven = true;
copy3(*params->location, data.center);
}
// If radius given
if (params->radius1 > 0 ) {
data.radiusGiven = true;
data.radius = params->radius1;
}
// Copy possible defining points
data.nofDefiningPoints = params->nofDefiningPoints;
if ( data.nofDefiningPoints > 0 ) {
data.definingPoints = new Point3[data.nofDefiningPoints];
for (int i = 0; i < data.nofDefiningPoints; i++) {
for (int j = 0; j < 3; j++) {
data.definingPoints[i][j] = params->definingPoints[i][j];
}
}
}
data.deltaType = lin_delta_type;
data.delta = lin_delta;
// Set final data parameters
// -------------------------
if ( !updateData() ) return false;
setDeltaU(lin_delta_type, lin_delta);
nofBoundaryPoints = 0;
boundaryPoints = NULL;
return true;
}
void
GcCircle::getDiscretizationData(int& nof_components, linDeltaType*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = 1;
types = new enum linDeltaType[1];
types[0] = data.deltaType;
valuesU = new double[1];
valuesU[0] = data.delta;
valuesV = NULL;
useFixedN = new bool[1];
useFixedN[0] = data.useFixedMeshN;
}
bool
GcCircle::getLine(int index, GcLine*& line)
{
if ( index < 0 || index >= nofBoundaryPoints - 1) {
return false;
}
Point3* p1 = boundaryPoints[index]->point->getPoint();
Point3* p2 = boundaryPoints[index + 1]->point->getPoint();
line = new GcLine(p1, p2);
return true;
}
void
GcCircle::init(bool do_linearize)
{
if (do_linearize) {
calcBoundaryPoints();
}
boundbox = calcBoundBox();
}
// Destructor.
GcCircle::~GcCircle()
{
delete[] vertexTags;
}
// Calculates bounding box for the circle.
BoundBox*
GcCircle::calcBoundBox()
{
RangeVector range;
BoundBox* bbox = new BoundBox;
Point3* bp1;
Point3* bp2;
if ( nofBoundaryPoints == 0 ) {
calcBoundaryPoints();
}
// Arc
if ( !data.isClosed ) {
for (int i = 0; i < nofBoundaryPoints; i++) {
bbox->extendByPoint(boundaryPoints[i]->point);
}
// Full circle
} else {
RangeVector rv;
rv[0] = data.center[0] - data.radius;
rv[1] = data.center[0] + data.radius;
rv[2] = data.center[1] - data.radius;
rv[3] = data.center[1] + data.radius;
rv[4] = 0;
rv[5] = 0;
bbox->extendByRange(rv);
}
return bbox;
}
// Calculate linearized boundary
// Store result in the points-buffer
// NOTE: Buffer is allocated here, client should take care of its deletion!!!
//
void
GcCircle::calcLinearizingPoints(int& nof_points, GcPoint**& points, double delta_u)
{
nof_points = 0;
points = NULL;
PointList all_points;
// NOTE: Start point is added already here
//
all_points.push_back(data.start);
calcLinearizingPoints(data.start_u, data.end_u, delta_u, all_points);
// NOTE: End point is added not until here
//
if ( data.isClosed ) {
all_points.push_back(data.start);
} else {
all_points.push_back(data.end);
}
//---Collect all points to the result
nof_points = all_points.size();
points = new GcPoint*[nof_points];
PointList::iterator itr = all_points.begin();
for (int i = 0; i < nof_points; i++, itr++) {
points[i] = *itr;
}
}
// Helper function
//
void
GcCircle::calcLinearizingPoints(double start_u, double end_u, double delta_u, PointList& all_points)
{
//-If no positive delta_u given, use the default
if (delta_u <= 0) {
delta_u = deltaU;
}
//-Create points
double pos_u = start_u + delta_u;
while (true) {
// At end!
if ( isEqual(pos_u, end_u) || isGreater(pos_u, end_u)) {
break;
}
double x = data.radius * cos(pos_u) + data.center[0];
double y = data.radius * sin(pos_u) + data.center[1];
double z = 0.0;
all_points.push_back(new GcPoint(x, y, z));
pos_u += delta_u;
}
}
void
GcCircle::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
const Point3* p1;
const Point3* p2;
int n;
// A pair of consequtive points as a line
if ( direction == 1 ) {
for (n = 0; n < nofBoundaryPoints-1; n++) {
p1 = boundaryPoints[n]->point->getPoint();
p2 = boundaryPoints[n+1]->point->getPoint();
renderer->drawLine(dmode, dstate, 1, p1, p2, elem_id);
}
} else {
for (n = nofBoundaryPoints-1; n > 0; n--) {
p1 = boundaryPoints[n]->point->getPoint();
p2 = boundaryPoints[n-1]->point->getPoint();
renderer->drawLine(dmode, dstate, 1, p1, p2, elem_id);
}
}
}
#if 0
void
GcCircle::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
const Point3* p1;
const Point3* p2;
int n;
// A pair of consequtive points as a line
if ( direction == 1 ) {
for (n = 0; n < nofLinearizingPoints-1; n++) {
p1 = linearizingPoints[n]->getPoint();
p2 = linearizingPoints[n+1]->getPoint();
renderer->drawLine(dmode, dstate, 1, p1, p2, elem_id);
}
} else {
for (n = nofLinearizingPoints-1; n > 0; n--) {
p1 = linearizingPoints[n]->getPoint();
p2 = linearizingPoints[n-1]->getPoint();
renderer->drawLine(dmode, dstate, 1, p1, p2, elem_id);
}
}
}
#endif
#if 0
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns a structure where there is the nof intersection and
// the minimum x-coordinate for the intersections.
RayHit*
GcCircle::isectionsWithXdir(GcPoint* xdir_startp, bool& negative_on_left)
{
RayHit* result = new RayHit;
negative_on_left = false;
result->count = 0;
result->min_value = 1.0e+100;
int nof_values;
double* values;
isectionsWithXdir(xdir_startp, nof_values, values, negative_on_left);
result->count = nof_values;
for (int i = 0; i < nof_values; i++) {
if ( isLess(values[i], result->min_value) ) {
result->min_value = values[i];
}
}
if (result->count == 0) {
delete result;
result = NULL;
}
delete[] values;
return result;
}
#endif
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns a structure where there is the nof intersection and
// the minimum x-coordinate for the intersections.
RayHit*
GcCircle::isectionsWithXdir(GcPoint* xdir_startp, bool& negative_on_left)
{
RayHit* result = new RayHit;
int index = 0;
GcLine* line;
while (true) {
// No more lines!
if ( !getLine(index++, line) ) {
break;
}
bool neg_on_left;
RayHit* hits = line->isectionsWithXdir(xdir_startp, neg_on_left);
if ( hits != NULL ) {
result->count++;
result->points.push_back(hits->points.front());
if ( hits->min_value < result->min_value ) {
result->min_value = hits->min_value;
// NOTE: Negative on left indicator is picked
// from the "leftmost" hit, this way we can conclude the
// possible loop orientation correctly
negative_on_left = neg_on_left;
}
}
delete line;
delete hits;
}
if (result->count == 0) {
delete result;
result = NULL;
}
return result;
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns nof-intersection and the corresponding x-values in the arguments
void
GcCircle::isectionsWithXdir(GcPoint* xdir_startp, int& nof_values , double*& values)
{
nof_values = 0;
// Intersection point(s):
// line_x = center[0] + radius * sin(u)
// line_y = center[1] + radius * cos(u)
double px = xdir_startp->Pos(X);
double py = xdir_startp->Pos(Y);
// If no chances!
if ( isGreater(py, data.center[1] + data.radius) ||
isLess(py, data.center[1] - data.radius)
) {
return;
}
values = new double[2];
// Line-y is constant:
// cos(u) = (line_y - center[1]) / radius
double u1 = asin( (py - data.center[1]) / data.radius );
double u2 = PI - u1; // Other possible solution
// X values
// ========
if ( !isLess(u1, data.start_u) || !isGreater(u1, data.end_u) ) {
values[nof_values++] = data.center[0] + data.radius * cos(u1);
}
if ( !isLess(u2, data.start_u) || !isGreater(u2, data.end_u) ) {
values[nof_values++] = data.center[0] + data.radius * cos(u2);
}
// Make the nearest intersection point the first
if ( nof_values == 2 ) {
double d1 = fabs(values[0] - px);
double d2 = fabs(values[1] - px);
if ( isLess(d2, d1) ) {
double tmp = values[0];
values[0] = values[1];
values[1] = tmp;
}
}
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and y-axis and which starts from point *startp* towards right.
// Returns nof-intersection and the corresponding y-values in the arguments
void
GcCircle::isectionsWithYdir(GcPoint* ydir_startp, int& nof_values , double*& values)
{
nof_values = 0;
// Intersection point(s):
// line_x = center[0] + radius * sin(u)
// line_y = center[1] + radius * cos(u)
double px = ydir_startp->Pos(X);
double py = ydir_startp->Pos(Y);
// If no chances!
if ( isGreater(px, data.center[0] + data.radius) ||
isLess(px, data.center[0] - data.radius)
) {
return;
}
values = new double[2];
// Line-x is constant:
// sin(u) = (line_x - center[0]) / radius
double u1 = acos( (px - data.center[0]) / data.radius );
double u2 = -u1; // Other possible solution
// Y-values
// ========
if ( !isLess(u1, data.start_u) || !isGreater(u1, data.end_u) ) {
values[nof_values++] = data.center[1] + data.radius * sin(u1);
}
if ( !isLess(u2, data.start_u) || !isGreater(u2, data.end_u) ) {
values[nof_values++] = data.center[1] + data.radius * sin(u2);
}
}
ostream&
GcCircle::output_emf(ostream& out, short indent_size, short indent_level)
{
const char* def;
LibFront::output_scalar(out, indent_size, indent_level, EMF_GEOMETRY, NULL, "Circle", true);
if ( nofVertices > 0 ) {
LibFront::output_vector(out, indent_size, indent_level, EMF_VERTICES, NULL, nofVertices, vertexTags, false);
}
def = getMatcString(data.matcTable, EMF_CENTER);
if ( model->keepMatcDefinitions() && def != NULL ) {
LibFront::output_matcDef(out, indent_size, indent_level, EMF_CENTER, NULL, def);
} else {
LibFront::output_vector(out, indent_size, indent_level, EMF_CENTER, NULL, 3, data.center, false);
}
def = getMatcString(data.matcTable, EMF_RADIUS);
if ( model->keepMatcDefinitions() && def != NULL ) {
LibFront::output_matcDef(out, indent_size, indent_level, EMF_RADIUS, NULL, def);
} else {
LibFront::output_scalar(out, indent_size, indent_level, EMF_RADIUS, NULL, data.radius);
}
if ( data.deltaType != LIN_DELTA_NONE && data.delta > 0.0 ) {
switch ( data.deltaType ) {
case LIN_DELTA_H:
LibFront::output_scalar(out, indent_size, indent_level, EMF_DELTA_H, NULL, data.delta);
break;
case LIN_DELTA_N:
LibFront::output_scalar(out, indent_size, indent_level, EMF_DELTA_N, NULL, int(data.delta));
break;
case LIN_DELTA_U:
LibFront::output_scalar(out, indent_size, indent_level, EMF_DELTA_U, NULL, data.delta);
break;
}
}
if ( data.useFixedMeshN ) {
LibFront::output_scalar(out, indent_size, indent_level, EMF_USE_MESH_N, NULL, 1);
}
return out;
}
// Calculate the point corresponding parametric values given as arguments.
// NOTE: Argument parameters are in [0,1], but circle's own parametric
// representation is between [0, 2PI]
void
GcCircle::param2Point(double u_p, double v_p, Point3& point)
{
double u = data.start_u + u_p * (data.end_u - data.start_u);
param2Point_own(u, point);
}
// Calculate the point corresponding paramtric values given as arguments.
// NOTE: Argument parameters are in [0,1], but circle's own parametric
// representation is between [0, 2PI]
GcPoint*
GcCircle::param2Point(double u_p, double v_p)
{
Point3 pp;
double u = data.start_u + u_p * (data.end_u - data.start_u);
param2Point_own(u, pp);
GcPoint* p = new GcPoint(pp);
return p;
}
// Calculate the point corresponding circle's own paramtric values given as argument.
// NOTE: Argument parameters are in [0,2PI]
bool
GcCircle::param2Point_own(double u, Point3& point)
{
if (u < data.start_u || u > data.end_u)
return false;
point[0] = data.radius * cos(u) + data.center[0];
point[1] = data.radius * sin(u) + data.center[1];
point[2] = 0.0;
return true;
}
// Parameter value for the point (0...1)
void
GcCircle::point2Param(Point3*point, double& u, double& v)
{
Point3 p;
if ( isClosedU() ) {
Point3 sp;
param2Point(0, 0, sp);
diff3(*point, sp, p);
} else {
diff3(*point, *data.start->getPoint(), p);
}
double len = length3(p);
if ( isZero(len) ) {
u = 0.0;
} else {
// "Center angle" is twice the "arc angle"
u = 2 * asin(len / (2 * data.radius));
}
if ( p[1] < 0 ) {
u = TWO_PI - u;
}
// Normed 0...1
u = u / (data.end_u - data.start_u);
v = 0.0;
}
// Calculates the paramtetric values corresponding the argument-point.
ParamPair*
GcCircle::point2Param(GcPoint* point)
{
double u, v;
point2Param(point->getPoint(), u, v);
// Point not in the circle
if ( u < 0 ) {
return NULL;
} else {
ParamPair* ppair = new ParamPair;
ppair->u = u;
ppair->v = v;
return ppair;
}
}
// NOTE: Do not update data-structure values in this function
// This should be called after data-structure values are set!!!
//
void
GcCircle::setDeltaU(enum linDeltaType lin_delta_type, double lin_delta)
{
double arc_angle = data.end_u - data.start_u;
// Max delta-h arc is limited to a half circle
double max_angle = min(PI, arc_angle);
double max_h = 2 * data.radius * sin(max_angle / 2);
double delta_h;
int delta_n;
double delta_u;
// Linearization
switch (lin_delta_type) {
case LIN_DELTA_H:
// Check that given delta-h is not too large
delta_h = min(max_h, lin_delta);
delta_u = 2 * asin( delta_h / (data.radius * 2) );
break;
case LIN_DELTA_N:
delta_u = arc_angle / lin_delta;
break;
case LIN_DELTA_U:
delta_u = lin_delta * arc_angle;
break;
case LIN_DELTA_NONE:
default:
int n = int(arc_angle / (TWO_PI / 72) + 0.5);
delta_u = arc_angle / n;
break;
}
// Make an equidistance division
delta_n = int(0.5 + arc_angle / delta_u);
// If full circle, we need at least three edges to
// linearize it
if ( data.isClosed ) {
delta_n = (delta_n < 3)?3:delta_n;
}
deltaU = arc_angle / delta_n;
deltaH = 2 * data.radius * sin(0.5 * deltaU);
}
void
GcCircle::setDiscretizationData(int nof_components, linDeltaType* types, double* valuesU, double* valuesV, bool* useFixedN)
{
if ( nof_components = 0 ) return;
data.deltaType = types[0];
data.delta = valuesU[0];
data.useFixedMeshN = useFixedN[0];
// Update also deltaU which is always in radians
//
setDeltaU(data.deltaType, data.delta);
}
bool
GcCircle::updateData()
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm;
// Calc center if not given
// ------------------------
// NOTE: We need 2 or 3 points for this, depending if the radius is
// given or not!
//
if (!data.centerGiven) {
Point3 *p1, *p2, *p3;
p1 = p2 = p3 = NULL;
//--Pick the two points anyway needed
//
// For an arc we can use the two vertices
if (!data.isClosed) {
p1 = data.start->getPoint();
p2 = data.end->getPoint();
// For a full circle we must have at least two defining points
} else if ( data.nofDefiningPoints >= 2 ) {
p1 = &(data.definingPoints[0]);
p2 = &(data.definingPoints[1]);
// ERROR: No way to calculate the Center!
} else {
strm << "Cannot calculate the circle center!" << ends;
gui->showMsg(strm.str());
return false;
}
//--Next use the radius or a third point
//
// If radius given, direction and two point is needed
if (data.radiusGiven) {
circle_center(data.radius, *p1, *p2, data.center);
// Otherwise we need the third point (we pick the last defining point for p3,
// first two must anyway be given and they were already used!)
} else if (data.nofDefiningPoints >= 3 ) {
p3 = &(data.definingPoints[data.nofDefiningPoints - 1]);
circle_center(*p1, *p2, *p3, data.center);
// ERROR: No way to calculate the Center!
} else {
strm << "Cannot calculate the circle center!" << ends;
gui->showMsg(strm.str());
return false;
}
}
// Calc radius if not given
// ------------------------
if ( !data.radiusGiven ) {
Point3* p = NULL;
if ( data.nofDefiningPoints > 0 ) {
p = &data.definingPoints[0];
} else if ( data.start != NULL ) {
p = data.start->getPoint();
} else if ( data.end != NULL ) {
p = data.end->getPoint();
}
// ERROR: No way to calculate the Radius!
if ( p == NULL ) {
strm << "Cannot calculate the circle radius!" << ends;
gui->showMsg(strm.str());
return false;
}
Point3 len;
diff3(*p, data.center, len);
data.radius = length3(len);
}
// Set parametrics
// ---------------
if ( data.radius > 0 ) {
//--Circle arc
if ( !data.isClosed ) {
// Normalize start
double start_x = (data.start->Pos(X) - data.center[X]) / data.radius;
double start_y = (data.start->Pos(Y) - data.center[Y]) / data.radius;
data.start_u = acos(start_x) * (start_y < 0?-1:1);
// Normalize end
double end_x = (data.end->Pos(X) - data.center[X]) / data.radius;
double end_y = (data.end->Pos(Y) - data.center[Y]) / data.radius;
data.end_u = acos(end_x) * (end_y < 0?-1:1);
if (data.end_u < data.start_u) {
data.end_u += TWO_PI;
}
//--Full circle
} else {
Point3 p;
param2Point(0.0, 0.0, p);
data.start = new GcPoint(p);
data.end = new GcPoint(p);
}
// ERROR: Radius is zero!
} else {
strm << "Circle radius is zero!" << ends;
gui->showMsg(strm.str());
return false;
}
return true;
}
// Update geometry. Relevant when Matc-parameters have been changed!
//
bool
GcCircle::updateGeometry(int parent_tag, IdList& vertex_tags)
{
static char buffer[1025];
const char* def;
char* val;
def = getMatcString(data.matcTable, EMF_CENTER);
if ( def != NULL ) {
val = mtc_domath((char*)def);
if ( val != NULL && val[0] != '\0' && !LibFront::isMatcError(val) ) {
strstream strm;
strm << val << ends;
strm >> data.center[0] >> data.center[1] >> data.center[2];
}
}
def = getMatcString(data.matcTable, EMF_RADIUS);
if ( def != NULL ) {
val = mtc_domath((char*)def);
if ( val != NULL && val[0] != '\0' && !LibFront::isMatcError(val) ) {
strstream strm;
strm << val << ends;
strm >> data.radius;
}
}
def = getMatcString(data.matcTable, EMF_START_POINT);
if ( def != NULL ) {
val = mtc_domath((char*)def);
if ( val != NULL && val[0] != '\0' && !LibFront::isMatcError(val) ) {
data.start->setPos(val);
}
}
def = getMatcString(data.matcTable, EMF_END_POINT);
if ( def != NULL ) {
val = mtc_domath((char*)def);
if ( val != NULL && val[0] != '\0' && !LibFront::isMatcError(val) ) {
data.end->setPos(val);
}
}
def = getMatcString(data.matcTable, EMF_MESH_H);
if ( def != NULL ) {
val = mtc_domath((char*)def);
if ( val != NULL && val[0] != '\0' && !LibFront::isMatcError(val) ) {
strstream strm;
strm << val << ends;
strm >> data.delta;
}
}
def = getMatcString(data.matcTable, EMF_MESH_N);
if ( def != NULL ) {
val = mtc_domath((char*)def);
if ( val != NULL && val[0] != '\0' && !LibFront::isMatcError(val) ) {
strstream strm;
strm << val << ends;
strm >> data.delta;
}
}
if ( !updateData() ) return false;
setDeltaU(data.deltaType, data.delta);
init(true);
calcBoundaryPoints();
return true;
}
//**************************
//*****GcLine methods *****
//**************************
GcLine::GcLine(ecif_ElementComponent_X& tx, IdList& vertex_tags)
{
nofVertices = 2;
vertexTags = new int[2];
GcPoint** points = new GcPoint*[2];
for (int i = 0; i < 2; i++) {
int vtag = tx.vertex_tags[i];
vertexTags[i] = vtag;
vertex_tags.push_back(vtag);
BodyElement* v = model->getVertexByTag(vtag);
points[i] = (GcPoint*)v->getGeometry();
}
data.hasVertexTies = true;
data.useFixedMeshN = (bool)tx.use_fixed_mesh_n;
create(points[0], points[1]);
delete[] points;
copyMatcValueTable(tx.matcTable, data.matcTable);
}
// Constructor
GcLine::GcLine(BodyElement* vertex1, BodyElement* vertex2)
{
nofVertices = 2;
vertexTags = new int[2];
vertexTags[0] = vertex1->Tag();
vertexTags[1] = vertex2->Tag();
GcPoint* gp1 = (GcPoint*)vertex1->getGeometry();
GcPoint* gp2 = (GcPoint*)vertex2->getGeometry();
data.hasVertexTies = true;
create(gp1, gp2);
}
// Constructor
// NOTE: no vertices
GcLine::GcLine(Point3* p1, Point3* p2)
{
GcPoint* gp1 = new GcPoint(p1);
GcPoint* gp2 = new GcPoint(p2);
create(gp1, gp2);
}
// Create line
void
GcLine::create(GcPoint* gp1, GcPoint* gp2)
{
data.start = gp1;
data.end = gp2;
updateData();
}
#if 0
// Create line
void
GcLine::create(Point3* p1, Point3* p2)
{
data.start = new GcPoint(p1);
data.end = new GcPoint(p2);
Point3 len;
diff3(*(data.end->getPoint()), *(data.start->getPoint()), len);
data.length = length3(len);
data.dir = new GcPoint(len);
data.normal[0] = len[0];
data.normal[1] = len[1];
data.normal[2] = len[2];
normalize(data.normal);
double tmp = data.normal[0];
data.normal[0] = -data.normal[1];
data.normal[1] = tmp;
boundbox = calcBoundBox();
}
#endif
// Destructor.
GcLine::~GcLine()
{
//delete[] vertexTags;
}
// Calculates bounding box for the line.
BoundBox*
GcLine::calcBoundBox()
{
RangeVector range;
range[0] = data.start->Pos(X);
range[1] = data.end->Pos(X);
range[2] = data.start->Pos(Y);
range[3] = data.end->Pos(Y);
range[4] = data.start->Pos(Z);
range[5] = data.end->Pos(Z);
BoundBox* bbox = new BoundBox(range);
return bbox;
}
#if 0
void
GcLine::calcLinearizingPoints(int& nof_points_u, int& nof_points_v, GcPoint**& points, double delta_u, double delta_v)
{
PointList all_points;
calcEdgePoints(data.start_u, data.end_u, all_points);
//---Add line end-point
all_points.push_back(data.end);
//---Collect all points to the result
nof_points_u = all_points.size();
nof_points_v = 0;
points = new GcPoint*[nof_points_u];
PointList::iterator itr = all_points.begin();
for (int i = 0; i < nof_points_u; i++, itr++) {
points[i] = *itr;
}
}
#endif
#if 0
void
GcLine::calcLinearizingPoints(int& nof_points_u, int& nof_points_v, GcPoint**& points, double delta_u, double delta_v)
{
nof_points_v = 0;
if ( nofPatterns == 0 ) {
nof_points_u = 2;
points = new GcPoint*[2];
points[0] = data.start;
points[1] = data.end;
return;
}
// Points with patterns
// ====================
PointList all_points;
all_points.push_back(data.start);
GcPoint* ebase = data.start;
calcEdgePointsWithPatterns(this, ebase, nofPatterns, patterns, all_points);
//---Remove last point from the list if it at the line end point
GcPoint* lastp = *(--all_points.end());
if ( ((*data.end) == *lastp) ) {
all_points.pop_back();
}
//---Add line end-point
all_points.push_back(data.end);
//---Collect all points to the result
nof_points_u = all_points.size();
points = new GcPoint*[nof_points_u];
PointList::iterator itr = all_points.begin();
for (int i = 0; i < nof_points_u; i++, itr++) {
points[i] = *itr;
}
}
#endif
void
GcLine::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
const Point3* p1;
const Point3* p2;
p1 = data.start->getPoint();
p2 = data.end->getPoint();
renderer->drawLine(dmode, dstate, direction, p1, p2, elem_id);
}
void
GcLine::getDiscretizationData(int& nof_components, linDeltaType*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = 1;
types = NULL;
valuesU = NULL;
valuesV = NULL;
useFixedN = new bool[1];
useFixedN[0] = data.useFixedMeshN;
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns a structure where there is the nof intersection and
// the minimum x-coordinate for the intersections.
// (For a line-segment (as this one) nof intersections is of course 0 or 1)
//
RayHit*
GcLine::isectionsWithXdir(GcPoint* xdir_startp, bool& negative_on_left)
{
// Parameters t,w are solutions for the following equations:
// csx + t = clx + klx * w;
// csy = cly + kly * w;
// csz = clz + kly * w;
negative_on_left = false;
// Constant parameters for *xdir_startp*-line:
double csx = xdir_startp->Pos(X);
double csy = xdir_startp->Pos(Y);
double csz = xdir_startp->Pos(Z);
// Constant parameters for *this*-line:
double clx = data.start->Pos(X);
double cly = data.start->Pos(Y);
double clz = data.start->Pos(Z);
// Deflection parameters for *this*-line:
double klx = data.dir->Pos(X);
double kly = data.dir->Pos(Y);
double klz = data.dir->Pos(Z);
// Lines are parallel (klx !=0 and kly = 0)
if ( ( klx < -EPSILON || klx > EPSILON) &&
( kly > -EPSILON && kly < EPSILON)
) {
return NULL;
}
// Intersection-point's domain-parametervalue on *this*-line:
double w;
if ( kly != 0 ) {
w = (csy - cly) / kly;
} else {
w = 0.0;
}
// If w not in (0,1), intersection-point can't be on *this*-line.
if (w < -EPSILON || w > 1+EPSILON) return NULL;
// Intersection-point's domain-parametetrvalue on *xdir_startp*-line.
// It should be positive because we are looking only to right:
double t = (clx - csx) + klx * w;
if (t < -EPSILON ) return NULL;
RayHit* result = new RayHit;
Point3* p = new Point3[1];
(*p)[0] = clx + klx * w;
(*p)[1] = cly + kly * w;
(*p)[2] = clz + klz * w;
result->count = 1;
result->points.push_back(p);
result->min_value = csx + t;
negative_on_left = kly > 0;
return result;
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp*.
// Returns the intersection x-coordinate value in the argument
// (For a line-segment (as this one) nof intersections is of course 0 or 1)
void
GcLine::isectionsWithXdir(GcPoint* xdir_startp, int& nof_values, double*& values)
{
// Parameters t,w are solution for the following equations:
// csx + t = clx + klx * w;
// csy = cly + kly * w;
// csz = clz + kly * w;
nof_values = 0;
// Constant parameters for *xdir_startp*-line:
double csx = xdir_startp->Pos(X);
double csy = xdir_startp->Pos(Y);
double csz = xdir_startp->Pos(Z);
// Constant parameters for *this*-line:
double clx = data.start->Pos(X);
double cly = data.start->Pos(Y);
double clz = data.start->Pos(Z);
// Deflection parameters for *this*-line:
double klx = data.dir->Pos(X);
double kly = data.dir->Pos(Y);
double klz = data.dir->Pos(Z);
// Lines are parallel (klx !=0 and kly = 0)
if ( !isZero(klx) && isZero(kly) ) {
return;
}
// Intersection-point's domain-parametervalue on *this*-line:
double w;
if ( !isZero(kly) ) {
w = (csy - cly) / kly;
} else {
w = 0.0;
}
// If w not in (0,1), intersection-point can't be on *this*-line.
if ( isLess(w, 0.0) || isGreater(w, 1.0) ) {
return;
}
// Intersection-point's domain-parametetrvalue on *xdir_startp*-line.
double t = (clx - csx) + klx * w;
// Set result values
nof_values = 1;
values = new double[1];
values[0] = csx + t;
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and y-axis and which starts from point *startp*.
// Returns the intersection x-coordinate value in the argument
// (For a line-segment (as this one) nof intersections is of course 0 or 1)
void
GcLine::isectionsWithYdir(GcPoint* ydir_startp, int& nof_values, double*& values)
{
// Parameters t,w are soluition for the following equations:
// csx + t = clx + klx * w;
// csy = cly + kly * w;
// csz = clz + kly * w;
nof_values = 0;
// Constant parameters for *xdir_startp*-line:
double csx = ydir_startp->Pos(X);
double csy = ydir_startp->Pos(Y);
double csz = ydir_startp->Pos(Z);
// Constant parameters for *this*-line:
double clx = data.start->Pos(X);
double cly = data.start->Pos(Y);
double clz = data.start->Pos(Z);
// Deflection parameters for *this*-line:
double klx = data.dir->Pos(X);
double kly = data.dir->Pos(Y);
double klz = data.dir->Pos(Z);
// Lines are parallel (klx =0 and kly != 0)
if ( isZero(klx) && !isZero(kly) ) {
return;
}
// Intersection-point's domain-parametervalue on *this*-line:
double w;
if ( !isZero(klx) ) {
w = (csx - clx) / klx;
} else {
w = 0.0;
}
// If w not in (0,1), intersection-point can't be on *this*-line.
if ( isLess(w, 0.0) || isGreater(w, 1.0) ) {
return;
}
// Intersection-point's domain-parametetrvalue on *xdir_startp*-line.
double t = (cly - csy) + kly * w;
// Set result values
nof_values = 1;
values = new double[1];
values[0] = csy + t;
}
bool
GcLine::isOnSameAxis(GcPoint& p1, GcPoint& p2)
{
GcPoint dir_12 = p1 - p2;
GcPoint dir_1s = p1 - *data.start;
return ( dir_12.isParallel(data.dir) &&
dir_1s.isParallel(data.dir) );
}
ostream&
GcLine::output_emf(ostream& out, short indent_size, short indent_level)
{
LibFront::output_vector(out, indent_size, indent_level, "Vertices", NULL, nofVertices, vertexTags, false);
if ( data.useFixedMeshN ) {
LibFront::output_scalar(out, indent_size, indent_level, EMF_USE_MESH_N, NULL, 1);
}
return out;
}
// Calculate the point corresponding the paramtric values given as arguments.
void
GcLine::param2Point(double u_p, double v_p, Point3& point)
{
// For line only parametr *u_p* is relevant.
point[0] = data.start->Pos(X) + ( u_p * data.dir->Pos(X));
point[1] = data.start->Pos(Y) + ( u_p * data.dir->Pos(Y));
point[2] = data.start->Pos(Z) + ( u_p * data.dir->Pos(Z));
}
// Calculate the point corresponding the paramtric values given as arguments.
GcPoint*
GcLine::param2Point(double u_p, double v_p)
{
// For line only parametr *u_p* is relevant.
double x = data.start->Pos(X) + ( u_p * data.dir->Pos(X));
double y = data.start->Pos(Y) + ( u_p * data.dir->Pos(Y));
double z = data.start->Pos(Z) + ( u_p * data.dir->Pos(Z));
GcPoint* p = new GcPoint(x,y,z);
return p;
}
void
GcLine::point2Param(Point3* point, double& u, double& v)
{
Point3* start = data.start->getPoint();
Point3* end = data.end->getPoint();
// Start point
if ( samepoint(*point, *start) ) {
u = 0;
// End point
} else if ( samepoint(*point, *end) ) {
u = 1;
// Point is possibly within line
} else {
Point3 len;
Point3 part;
diff3(*end, *start, len);
diff3(*point, *start, part);
// We return negative value if the point is not
// geometrically on the line
Point3 p;
cross3(len, part, p);
if ( !isZero(length3(p)) ) {
u = -1.0;
// Now we can pick the parameter value from the first nonzero component.
} else if ( !isZero(len[0]) ) {
u = part[0] / len[0];
} else if ( !isZero(len[1]) ) {
u = part[1] / len[1];
} else {
u = 0.0;
}
}
v = 0.0;
}
// Calculates the paramtetric values corresponding the argument-point.
ParamPair*
GcLine::point2Param(GcPoint* p)
{
double u, v;
point2Param(p->getPoint(), u, v);
// Point not in the line!
if ( u < 0 ) {
return NULL;
} else {
// Create the result-object.
ParamPair* ppair = new ParamPair;
ppair->u = u;
ppair->v = v;
return ppair;
}
}
void
GcLine::setDiscretizationData(int nof_components, linDeltaType* types, double* valuesU, double* valuesV, bool* useFixedN)
{
if ( nof_components = 0 ) return;
data.useFixedMeshN = useFixedN[0];
}
bool
GcLine::updateData()
{
Point3 len;
diff3(*(data.end->getPoint()), *(data.start->getPoint()), len);
data.length = length3(len);
data.dir = new GcPoint(len);
data.normal[0] = len[0];
data.normal[1] = len[1];
data.normal[2] = len[2];
normalize(data.normal);
double tmp = data.normal[0];
data.normal[0] = -data.normal[1];
data.normal[1] = tmp;
boundbox = calcBoundBox();
return true;
}
// Update geometry. Relevant when Matc-parameters have been changed!
//
bool
GcLine::updateGeometry(int parent_tag, IdList& vertex_tags)
{
return updateData();
}
//****************************
//***** GcMulti2D methods ****
//****************************
GcMulti2D::GcMulti2D(ecif_Element_X& tx, IdList& vertex_tags)
{
int i,j;
data.nofComponents = tx.nof_components;
data.components = new Geometry2D*[data.nofComponents];
int final_nof_cmpnts = 0;
for (i = 0; i < data.nofComponents; i++) {
data.components[i] = NULL;
Geometry2D* ptrGmtr = NULL;
switch ( tx.components[i]->gmtr_type ) {
case ECIF_CIRCLE:
//-Function circle
//
if ( tx.components[i]->isFunction ) {
if ( tx.components[i]->isCpp )
ptrGmtr = createFunctionCircleC(tx.tag, *tx.components[i], vertex_tags);
else if (tx.components[i]->isF95 )
;//ptrGmtr = createFunctionCircleF(tx.tag, *tx.components[i], vertex_tags);
else if (tx.components[i]->isMatc )
ptrGmtr = createFunctionCircleM(tx.tag, *tx.components[i], vertex_tags);
//-Normal circle
//
} else {
ptrGmtr = new GcCircle(*tx.components[i], vertex_tags);
}
break;
case ECIF_LINE:
ptrGmtr = new GcLine(*tx.components[i], vertex_tags);
break;
case ECIF_POLYLINE:
//-Function polyline
//
if ( tx.components[i]->isFunction ) {
if ( tx.components[i]->isCpp )
ptrGmtr = createFunctionPolyLineC(tx.tag, *tx.components[i], vertex_tags);
else if (tx.components[i]->isF95 )
;//ptrGmtr = createFunctionPolyLineF(tx.tag, *tx.components[i], vertex_tags);
else if (tx.components[i]->isMatc )
ptrGmtr = createFunctionPolyLineM(tx.tag, *tx.components[i], vertex_tags);
//-Normal polyline
//
} else {
ptrGmtr = new GcPolyLine(*tx.components[i], vertex_tags);
}
break;
case ECIF_NURBS:
ptrGmtr = new GcNurbsCurve(*tx.components[i], vertex_tags);
break;
default:
ptrGmtr = NULL;
break;
}
// Error in geometry!
//
if ( ptrGmtr == NULL || !ptrGmtr->geometryIsOk() ) {
delete ptrGmtr;
geometryOk = false;
return;
}
data.components[i] = ptrGmtr;
int ccount = ptrGmtr->getNofComponents();
final_nof_cmpnts += ccount;
}
// Init other data
init();
// Collect all (simple) components into one array
//
Geometry2D** tmp = new Geometry2D*[final_nof_cmpnts];
data.isDeletable = new bool[final_nof_cmpnts];
int idx = 0;
for (i = 0; i < data.nofComponents; i++) {
Geometry2D* pg = data.components[i];
// If a component is simple, take as it is
//
if ( !pg->isMultiGeometry() ) {
tmp[idx] = pg;
data.isDeletable[idx] = false;
idx++;
// If a component is a Multi2D, copy its subcomponents!
// NOTE: Sub components should have been already unpurged
// recursively!
//
} else {
for (j = 0; j < pg->getNofComponents(); j++) {
tmp[idx] = (Geometry2D*)pg->getComponent(j);
data.isDeletable[idx] = true;
idx++;
}
}
}
// Store original components as components to be output to
// emf file
//
data.nofEmfComponents = data.nofComponents;
data.emfComponents = data.components;
// These are components which all are geometry primitives (polylines,circles etc)
data.nofComponents = final_nof_cmpnts;
data.components = tmp;
// Finally linearize and calc boundbox
//
updateData();
}
// Destructor.
GcMulti2D::~GcMulti2D()
{
int i;
for (i = 0; i < data.nofComponents; i++) {
delete data.components[i];
data.components[i] = NULL;
}
for (i = 0; i < data.nofEmfComponents; i++) {
//delete data.emfComponents[i];
//data.emfComponents[i] = NULL;
}
}
// Calculates bounding box for the line.
BoundBox*
GcMulti2D::calcBoundBox()
{
return data.components[0]->calcBoundBox();
}
// Calculate linearized boundary
void
GcMulti2D::calcBoundaryPoints()
{
for (int i = 0; i < data.nofComponents; i++) {
data.components[i]->calcBoundaryPoints();
}
}
// Calculate linearized boundary
// Store result in the points-buffer
// NOTE: Buffer is allocated here, client should take care of its
// deletion!!!
void
GcMulti2D::calcLinearizingPoints(int& nof_points, GcPoint**& points, double delta_u)
{
for (int i = 0; i < data.nofComponents; i++) {
data.components[i]->calcLinearizingPoints(nof_points, points, delta_u);
}
}
// ================================================================
// C++-function calls
// ================================================================
//===========================
// Create egf function-CIRCLE
// ==========================
// C++-version
//
GcMulti2D*
GcMulti2D::createFunctionCircleC(int edge_tag, ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm, strm1, strm2;
int i,j;
bool is_ok = true;
Hdll hDLL = NULL; // Handle to DLL library
Hfunc hFunc = NULL; // Handle to dll function
char* err_msg = NULL;
is_ok = loadDllFunction(txc.libraryName, txc.functionName, hDLL, hFunc, err_msg);
int nof_circles = 0;
egf_Circle* circles = NULL;
dllCircleFunc userFunc;
if ( is_ok ) {
userFunc = (dllCircleFunc)hFunc;
} else {
strm2 << err_msg << endl;
}
// Ok, try to call the circle fucntion
if (is_ok ) {
int rc = userFunc(EGF_CIRCLE, txc.argc, txc.argv, txc.startPoint, txc.endPoint, nof_circles, circles);
// Error: function cal failed
if ( rc != 0 ) {
strm2 << "Function call failed with return code " << rc;
is_ok = false;
}
}
if ( is_ok && nof_circles == 0 ) {
is_ok = false;
strm2 << "Nof circles is zero!";
}
// Error
//
if ( !is_ok ) {
strm1 << "***ERROR in C++ circle function for edge " << edge_tag << ends;
strm2 << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
return NULL;
}
GcMulti2D* ptrG = createFunctionCircle(nof_circles, circles, txc, vertex_tags);
ptrG->data.funcType = ECIF_CPP;
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
if ( ptrG == NULL ) {
strm1 << "***ERROR in Front when processing circle function for edge " << edge_tag << ends;
gui->showMsg(strm1.str());
return NULL;
}
return ptrG;
}
// ============================
// Create egf function-POLYLINE
// ============================
// C++-version
//
GcMulti2D*
GcMulti2D::createFunctionPolyLineC(int edge_tag, ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm, strm1, strm2;
int i,j;
Hdll hDLL = NULL; // Handle to DLL library
Hfunc hFunc = NULL; // Handle to dll function
char* err_msg = NULL;
bool is_ok = loadDllFunction(txc.libraryName, txc.functionName, hDLL, hFunc, err_msg);
int nof_polylines = 0;
egf_PolyLine* polylines = NULL;
dllPolyLineFunc userFunc;
if ( is_ok ) {
userFunc = (dllPolyLineFunc)hFunc;
} else {
strm2 << err_msg << endl;
}
if ( is_ok ) {
int rc = userFunc(EGF_POLYLINE, txc.argc, txc.argv, txc.startPoint, txc.endPoint, nof_polylines, polylines);
// Error: function call failed
if ( rc != 0 ) {
strm2 << "Function call failed with return code " << rc;
is_ok = false;
}
}
if ( is_ok && nof_polylines == 0 ) {
is_ok = false;
strm2 << "Nof polylines is zero!";
}
// Error in library or function call, stop
// =======================================
if ( !is_ok ) {
strm1 << "***ERROR in C++ polyline function for edge " << edge_tag << ends;
strm2 << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
return NULL;
}
GcMulti2D* ptrG = createFunctionPolyLine(nof_polylines, polylines, txc, vertex_tags);
ptrG->data.funcType = ECIF_CPP;
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
if ( ptrG == NULL ) {
strm1 << "***ERROR in Front when processing polyline function for edge " << edge_tag << ends;
gui->showMsg(strm1.str());
return NULL;
}
return ptrG;
}
#if 0
// ================================================================
// Fortan95-function calls
// ================================================================
// ==========================
// Create egf function-CIRCLE
// ==========================
// F95-version
//
GcMulti2D*
GcMulti2D::createFunctionCircleF(int edge_tag, ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm, strm1, strm2;
int i,j;
bool is_ok = true;
Hdll hDLL; // Handle to DLL
int nof_circles = 0;
egf_Circle* circles = NULL;
// Load library
hDLL = LoadLibrary(txc.libraryName);
// Error, library not found
//
if (hDLL == NULL) {
is_ok = false;
strm2 << "Cannot open dll-library: " << txc.libraryName;
}
// Typedef for a safer function call
typedef int (Callbackp dllFunc)(int argc, double* argv,
egf_Point3* start, egf_Point3* end,
int& nof_circles, egf_Circle*& circles);
dllFunc userFunc; // Function pointer to the user's function
// Try first decorated name (_name@n)
strm << "_" << txc.functionName << "@24" << ends;
userFunc = (dllFunc)GetProcAddress(hDLL, strm.str());
// Next try undecorated name
if ( userFunc == NULL ) {
userFunc = (dllFunc)GetProcAddress(hDLL, txc.functionName);
}
//
if (is_ok ) {
// Error: function not found
if ( userFunc == NULL ) {
is_ok = false;
strm2 << "Cannot open function " << txc.functionName;
// Ok, try to call the function
} else {
int rc = userFunc(txc.argc, txc.argv, txc.startPoint, txc.endPoint, nof_circles, circles);
// Error: function cal failed
if ( rc != 0 ) {
strm2 << "Function call failed with return code " << rc;
is_ok = false;
}
}
}
if ( is_ok && nof_circles == 0 ) {
is_ok = false;
strm2 << "Nof circles is zero!";
}
// Error
//
if ( !is_ok ) {
strm1 << "***ERROR in F95 circle function for edge " << edge_tag << ends;
strm2 << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
return NULL;
}
GcMulti2D* ptrG = createFunctionCircle(nof_circles, circles, txc, vertex_tags);
ptrG->data.funcType = ECIF_F95;
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
if ( ptrG == NULL ) {
strm1 << "***ERROR in Front when processing polyline function for edge " << edge_tag << ends;
gui->showMsg(strm1.str());
return NULL;
}
return ptrG;
}
// ============================
// Create egf function-POLYLINE
// ============================
// F95-version
//
GcMulti2D*
GcMulti2D::createFunctionPolyLineF(int edge_tag, ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm, strm1, strm2;
int i,j;
Hdll hDLL = NULL; // Handle to DLL
// Typedef for a safer function call
typedef int (Callbackp dllFunc)(int argc, double* argv,
egf_Point3* start, egf_Point3* end,
int& nof_polylines, egf_PolyLine*& polylines);
dllFunc userFunc = NULL; // Function pointer to the user's function
int nof_polylines = 0;
egf_PolyLine* polylines = NULL;
bool is_ok = true;
// Load the library
hDLL = LoadLibrary(txc.libraryName);
// Error, library not found
if (hDLL == NULL) {
is_ok = false;
strm2 << "Cannot open dll-library: " << txc.libraryName;
}
if ( is_ok ) {
// Try first decorated name (_name@n)
strm << "_" << txc.functionName << "@24" << ends;
userFunc = (dllFunc)GetProcAddress(hDLL, strm.str());
// Next try undecorated name
if ( userFunc == NULL ) {
userFunc = (dllFunc)GetProcAddress(hDLL, txc.functionName);
}
}
if ( is_ok ) {
// Error: function not found
if ( userFunc == NULL ) {
is_ok = false;
strm2 << "Cannot open function " << txc.functionName;
// Ok, try to call the function
} else {
int rc = userFunc(txc.argc, txc.argv, txc.startPoint, txc.endPoint, nof_polylines, polylines);
// Error: function call failed
if ( rc != 0 ) {
strm2 << "Function call failed with return code " << rc;
is_ok = false;
}
}
}
if ( is_ok && nof_polylines == 0 ) {
is_ok = false;
strm2 << "Nof polylines is zero!";
}
// Error in library or function call, stop
// =======================================
if ( !is_ok ) {
strm1 << "***ERROR in F95 polyline function for edge " << edge_tag << ends;
strm2 << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
return NULL;
}
GcMulti2D* ptrG = createFunctionPolyLine(nof_polylines, polylines, txc, vertex_tags);
ptrG->data.funcType = ECIF_F95;
if ( hDLL != NULL ) {
closeDllLibrary(hDLL);
}
if ( ptrG == NULL ) {
strm1 << "***ERROR in Front when processing polyline function for edge " << edge_tag << ends;
gui->showMsg(strm1.str());
return NULL;
}
return ptrG;
}
#endif
// ================================================================
// Matc-function calls
// ================================================================
// ==========================
// Create egf function-CIRCLE
// ==========================
// Matc-version
//
GcMulti2D*
GcMulti2D::createFunctionCircleM(int edge_tag, ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm, strm1, strm2;
char* matc_result = NULL;
int i,j;
LibFront::initMatcFrmt();
bool is_ok = true;
int nof_circles = 0;
egf_Circle* circles = NULL;
// Check that matc function exists (call help("name")
//
strm << "help(\"";
// Copy function name until first left parnethesis
for (i = 0; i < strlen(txc.functionName) ; i++) {
char c = txc.functionName[i];
if ( c != '(' ) {
strm << c;
} else {
break;
}
}
strm << "\")" << ends;
char* fnm = strm.str();
if ( LibFront::isMatcError(mtc_domath(fnm)) ) {
is_ok = false;
strm2 << "MATC function: " << txc.functionName << " not defined!";
}
// Ok, try to call the function
if (is_ok ) {
matc_result = mtc_domath(txc.functionName);
//xc.argc, txc.argv, txc.startPoint, txc.endPoint, nof_circles, circles);
// Error: function call failed
if ( matc_result == NULL || matc_result[0] == '\0' ) {
strm2 << "***MATC ERROR: no value from circle function call: " << txc.functionName;
is_ok = false;
} else if ( LibFront::isMatcError(matc_result) ) {
LibFront::formatMatcError(matc_result);
strm2 << matc_result;
is_ok = false;
} else {
is_ok = getMatcCircleData(matc_result, nof_circles, circles, strm2);
}
}
if ( is_ok && nof_circles == 0 ) {
is_ok = false;
strm2 << "Nof circles is zero!";
}
// Error
//
if ( !is_ok ) {
strm1 << "***ERROR in Matc circle function for edge " << edge_tag << ends;
strm2 << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
return NULL;
}
GcMulti2D* ptrG = createFunctionCircle(nof_circles, circles, txc, vertex_tags);
ptrG->data.funcType = ECIF_MATC;
if ( ptrG == NULL ) {
strm1 << "***ERROR in Front when processing circle function for edge " << edge_tag << ends;
gui->showMsg(strm1.str());
return NULL;
}
return ptrG;
}
// ============================
// Create egf function-polyline
// ============================
// Matc-version
//
GcMulti2D*
GcMulti2D::createFunctionPolyLineM(int edge_tag, ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
UserInterface* gui = (UserInterface*)model->getGui();
strstream strm, strm1, strm2;
int i,j;
char* matc_result = NULL;
LibFront::initMatcFrmt();
int nof_polylines = 0;
egf_PolyLine* polylines = NULL;
bool is_ok = true;
// Check that matc function exists (call help("name")
//
strm << "help(\"";
// Copy function name until first left parnethesis
for (i = 0; i < strlen(txc.functionName); i++) {
char c = txc.functionName[i];
if ( c != '(' ) {
strm << c;
} else {
break;
}
}
strm << "\")" << ends;
char* fnm = strm.str();
if ( LibFront::isMatcError(mtc_domath(fnm)) ) {
is_ok = false;
strm2 << "MATC function: " << txc.functionName << " not defined!";
}
// Ok, try to call the polyline function
if (is_ok ) {
matc_result = mtc_domath(txc.functionName);
LibFront::trim(matc_result);
//int rc = userFunc(txc.argc, txc.argv, txc.startPoint, txc.endPoint, nof_polylines, polylines);
// Error: function call failed
if ( matc_result == NULL || matc_result[0] == '\0' ) {
strm2 << "***MATC ERROR: no value from polyline function call: " << txc.functionName;
is_ok = false;
} else if ( LibFront::isMatcError(matc_result) ) {
strm2 << matc_result;
is_ok = false;
} else {
is_ok = getMatcPolyLineData(matc_result, nof_polylines, polylines, strm2);
}
}
if ( is_ok && nof_polylines == 0 ) {
is_ok = false;
strm2 << "Nof polylines is zero!";
}
// Error in library or function call, stop
// =======================================
if ( !is_ok ) {
strm1 << "***ERROR in polyline function for edge " << edge_tag << ends;
strm2 << ends;
gui->showMsg(strm1.str());
gui->showMsg(strm2.str());
return NULL;
}
GcMulti2D* ptrG = createFunctionPolyLine(nof_polylines, polylines, txc, vertex_tags);
ptrG->data.funcType = ECIF_MATC;
if ( ptrG == NULL ) {
strm1 << "***ERROR in Front when processing polyline function for edge " << edge_tag << ends;
gui->showMsg(strm1.str());
return NULL;
}
return ptrG;
}
// Matc circle-function helper
//
bool
GcMulti2D::getMatcCircleData(const char* matc_result,
int& nof_circles, egf_Circle*& circles,
strstream& msg_strm)
{
int i,k;
nof_circles = 0;
circles = NULL;
int dim;
int radius_given;
int center_given;
int start_given;
int end_given;
int vflags_given;
strstream strm;
strm << matc_result << ends;
// These must always be in the matc-result
strm >> nof_circles >> dim;
strm >> radius_given >> center_given >> start_given >> end_given >> vflags_given;
// Not enough common parameter data!
//
int st = strm.fail();
if ( 0 != strm.fail() ) {
msg_strm << "Not enough parameter values for a Matc function circle";
return false;
}
if ( nof_circles == 0 ) return false;
if ( dim < 1 || dim > 3 ) {
msg_strm << "Illegal point dimension value for a Matc function circle (" << dim << ")";
return false;
}
circles = new egf_Circle[nof_circles];
for (i = 0; i < nof_circles; i++) {
// Not enough data!
//
if ( 0 != strm.eof() ) {
delete[] circles;
circles = NULL;
nof_circles = 0;
msg_strm << "Not enough data values for a Matc function circle";
return false;
}
egf_Circle* c = &(circles[i]);
if ( 0 != radius_given ) {
c->radiusGiven = true;
strm >> c->radius;
}
if ( 0 != center_given ) {
c->centerGiven = true;
for (k = 0; k < dim; k++) {
strm >> c->center[k];
}
}
if ( 0 != start_given ) {
c->startGiven = true;
for (k = 0; k < dim; k++) {
strm >> c->start[k];
}
}
if ( 0 != end_given ) {
c->endGiven = true;
for (k = 0; k < dim; k++) {
strm >> c->end[k];
}
}
if ( 0 != vflags_given ) {
strm >> c->vflags[0] >> c->vflags[1];
}
// Not enough data!
//
if ( 0 != strm.fail() ) {
delete[] circles;
circles = NULL;
nof_circles = 0;
msg_strm << "Not enough data values for a Matc function circle";
return false;
}
}
return true;
}
// Matc polyline-function helper
//
bool
GcMulti2D::getMatcPolyLineData(const char* matc_result,
int& nof_polylines, egf_PolyLine*& polylines,
strstream& msg_strm)
{
int i,k, nof_points;
int dim;
int vflags_given;
nof_polylines = 0;
polylines = NULL;
strstream strm;
strm << matc_result << ends;
// These must always be in the matc-result
strm >> nof_polylines >> dim >> vflags_given;
// Not enough common parameter data!
//
if ( 0 != strm.fail() ) {
msg_strm << "Not enough parameter values for Matc a function polyline";
return false;
}
if ( nof_polylines == 0 ) return false;
if ( dim < 1 || dim > 3 ) {
msg_strm << "Illegal point dimension value for a Matc function polyline (" << dim << ")";
return false;
}
polylines = new egf_PolyLine[nof_polylines];
// Read all polylines
//
for (i = 0; i < nof_polylines; i++) {
// Not enough data!
//
if ( strm.eof() ) {
delete[] polylines;
polylines = NULL;
nof_polylines = 0;
msg_strm << "Not enough data values for a Matc function polyline";
return false;
}
egf_PolyLine* c = &(polylines[i]);
strm >> nof_points;
c->points = new Point3[nof_points];
if ( 0 != vflags_given ) {
c->vflags = new int[nof_points];
}
// Read all polyline points and possible vertex flags
//
for (int n = 0; n < nof_points; n++) {
for (k = 0; k < dim; k++) {
strm >> c->points[n][k];
}
if ( 0 != vflags_given ) {
strm >> c->vflags[n];
}
}
if ( 0 != strm.fail() ) {
delete[] polylines;
polylines = NULL;
nof_polylines = 0;
msg_strm << "Not enough data values for a Matc function polyline";
return false;
}
}
return true;
}
// ================================================================
// Common calls
// ================================================================
// =============================
// Common create function-circle
// =============================
//
GcMulti2D*
GcMulti2D::createFunctionCircle(int nof_circles, egf_Circle* circles,
ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
// Try to create a new circle element
// ----------------------------------
try
{
ecif_Element_X ntx;
init_trx_data(ntx);
ntx.tplg_type = ECIF_EDGE;
ntx.nof_components = nof_circles;
ntx.components = new ecif_ElementComponent_X*[nof_circles];
GcPoint point;
int i,k;
for (i = 0; i < nof_circles; i++) {
// Create new sub-circle
ecif_ElementComponent_X* ntxc = new ecif_ElementComponent_X;
init_trx_data(*ntxc);
ntx.components[i] = ntxc;
ntxc->gmtr_type = ECIF_CIRCLE;
ntxc->lin_delta_type = txc.lin_delta_type;
ntxc->lin_delta[0] = txc.lin_delta[0];
ntxc->lin_delta[1] = txc.lin_delta[1];
ntxc->geometry.edge = new ecif_EdgeGeometry_X;
init_trx_data(*(ntxc->geometry.edge));
// Arguments
egf_Circle* c = &(circles[i]);
ntxc->geometry.edge->radius1 = c->radius;
if ( c->centerGiven ) {
ntxc->geometry.edge->location = new Point3[1];
for (k = 0; k < 3; k++) {
(*ntxc->geometry.edge->location)[k] = c->center[k];
}
}
if ( c->startGiven ) {
ntxc->geometry.edge->start = new Point3[1];
for (k = 0; k < 3; k++) {
(*ntxc->geometry.edge->start)[k] = c->start[k];
}
}
if ( c->endGiven ) {
ntxc->geometry.edge->end = new Point3[1];
for (k = 0; k < 3; k++) {
(*ntxc->geometry.edge->end)[k] = c->end[k];
}
}
if ( !c->startGiven ||
!c->endGiven ||
isZero(dist3(c->start, c->end))
) {
ntxc->geometry.edge->isClosed = true;
}
// Store vertex tags if start/end points flagged as vertex
ntxc->vertex_tags = new int[2];
ntxc->vertex_tags[0] = NO_INDEX;
ntxc->vertex_tags[1] = NO_INDEX;
//
//-Start point
if ( c->startGiven && 0 != c->vflags[0] ) {
point.setPos(c->start[0], c->start[1], c->start[2]);
BodyElement* v = model->findVertex(&point);
//-Create new vertex if needed
if ( v == NULL ) {
v = new BodyElement1D(&point);
model->addBodyElement(v);
}
ntxc->vertex_tags[0] = v->Tag();
}
//-End point
if ( c->endGiven && 0 != c->vflags[1] ) {
point.setPos(c->end[0], c->end[1], c->end[2]);
BodyElement* v = model->findVertex(&point);
//-Create new vertex if needed
if ( v == NULL ) {
v = new BodyElement1D(&point);
model->addBodyElement(v);
}
ntxc->vertex_tags[1] = v->Tag();
}
} // all circles
// Ok, create new Multi2D geometry from circles
GcMulti2D* ptrG = new GcMulti2D(ntx, vertex_tags);
if ( !ptrG->geometryIsOk() ) {
delete ptrG;
return NULL;
}
ptrG->data.delta = txc.lin_delta[0];
ptrG->data.deltaType = txc.lin_delta_type;
ptrG->data.useFixedMeshN = txc.use_fixed_mesh_n;
ptrG->data.gmtrType = ECIF_CIRCLE;
ptrG->data.functionName = NULL;
ptrG->data.libraryName = NULL;
update_dyna_string(ptrG->data.functionName, txc.functionName);
update_dyna_string(ptrG->data.libraryName, txc.libraryName);
ptrG->data.funcArgC = txc.argc;
ptrG->data.funcArgV = new double[txc.argc];
for (i = 0; i < txc.argc; i++) {
ptrG->data.funcArgV[i] = txc.argv[i];
}
copyMatcValueTable(txc.matcTable, ptrG->data.matcTable);
reset_trx_data(ntx);
return ptrG;
}
// Error in circle element
// -----------------------
catch (...)
{
return NULL;
}
} // End createFunctionCircle()
// ===============================
// Common create function-polyline
// ===============================
//
GcMulti2D*
GcMulti2D::createFunctionPolyLine(int nof_polylines, egf_PolyLine* polylines,
ecif_ElementComponent_X& txc,
IdList& vertex_tags)
{
int i,j;
// Try to create a new polyline element
// ---------------------------------
try
{
ecif_Element_X ntx;
init_trx_data(ntx);
ntx.tplg_type = ECIF_EDGE;
ntx.nof_components = nof_polylines;
ntx.components = new ecif_ElementComponent_X*[nof_polylines];
GcPoint point;
for (i = 0; i < nof_polylines; i++) {
// Create new sub-polyline
ecif_ElementComponent_X* ntxc = new ecif_ElementComponent_X;
init_trx_data(*ntxc);
ntx.components[i] = ntxc;
egf_PolyLine* c = &(polylines[i]);
int nof_points = c->nof_points;
ntxc->gmtr_type = ECIF_POLYLINE;
ntxc->lin_delta_type = txc.lin_delta_type;
ntxc->lin_delta[0] = txc.lin_delta[0];
ntxc->lin_delta[1] = txc.lin_delta[1];
ntxc->geometry.edge = new ecif_EdgeGeometry_X;
init_trx_data(*(ntxc->geometry.edge));
if ( isZero(dist3(c->points[0], c->points[nof_points-1])) ) {
ntxc->geometry.edge->isClosed = true;
}
ntxc->geometry.edge->nofDefiningPoints = nof_points;
ntxc->geometry.edge->definingPoints = new Point3[nof_points];
ntxc->geometry.edge->pointVertexFlags = new bool[nof_points];
// Count nof vertices
int nof_vertices = 0;
for (j = 0; j < nof_points; j++) {
if ( c->vflags[i] ) nof_vertices++;
}
ntxc->nof_vertices = nof_vertices;
ntxc->vertex_tags = new int[nof_vertices];
// Loop all polyline points
//
for (j = 0; j < nof_points; j++) {
// If point flagged as vertex, store coordinates
// also in the point-object (for finding the vertex)
for (short k = 0; k < 3; k++) {
double p = c->points[j][k];
if ( 1 == c->vflags[i] ) {
point.setPosit(k, p);
}
ntxc->geometry.edge->definingPoints[j][k] = p;
}
// Store vertex tag if point is flagged as vertex
//
if ( 1 == c->vflags[j] ) {
ntxc->geometry.edge->pointVertexFlags[j] = true;
BodyElement* v = model->findVertex(&point);
//-Create new vertex if needed
if ( v == NULL ) {
v = new BodyElement1D(&point);
model->addBodyElement(v);
}
ntxc->vertex_tags[j] = v->Tag();
} else {
ntxc->geometry.edge->pointVertexFlags[j] = false;
}
} // all polyline points
} // all polylines
// Create new Multi2D elements from polylines
GcMulti2D* ptrG = new GcMulti2D(ntx, vertex_tags);
ptrG->data.gmtrType = ECIF_POLYLINE;
ptrG->data.functionName = NULL;
ptrG->data.libraryName = NULL;
update_dyna_string(ptrG->data.functionName, txc.functionName);
update_dyna_string(ptrG->data.libraryName, txc.libraryName);
ptrG->data.funcArgC = txc.argc;
ptrG->data.funcArgV = new double[txc.argc];
for (i = 0; i < txc.argc; i++) {
ptrG->data.funcArgV[i] = txc.argv[i];
}
copyMatcValueTable(txc.matcTable, ptrG->data.matcTable);
reset_trx_data(ntx);
return ptrG;
}
// Error in polyline element
// ----------------------
catch (...)
{
return NULL;
}
} // End createFunctionPolyLine()
void
GcMulti2D::draw(int gmtr_index, Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
if ( gmtr_index < 0 || gmtr_index > data.nofComponents - 1 ) return;
Geometry* pg = data.components[gmtr_index];
if ( 1 == pg->getNofComponents() ) {
pg->draw(renderer, dmode, dstate, direction, elem_id);
} else {
pg->draw(gmtr_index, renderer, dmode, dstate, direction, elem_id);
}
}
void
GcMulti2D::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id, bool is_first_loop)
{
for (int i = 0; i < data.nofComponents; i++) {
data.components[i]->draw(renderer, dmode, dstate, direction, elem_id);
if ( i < data.nofComponents - 1 ) {
renderer->stopDrawingCadBodyElementLoop();
renderer->startDrawingCadBodyElementLoop(is_first_loop);
}
}
}
void
GcMulti2D::getBoundaryPoints(int& count, BoundaryPoint**& points)
{
count = getNofBoundaryPoints();
points = new BoundaryPoint*[count];
int index = 0;
for (int i = 0; i < data.nofComponents; i++) {
int countc;
BoundaryPoint** pointsc;
data.components[i]->getBoundaryPoints(countc, pointsc);
for (int j = 0; j < countc; j++) {
points[index++] = pointsc[j];
}
delete[] pointsc;
pointsc = NULL;
}
}
// NOTE: Argument flags tells if only one of the emf components (ie. components defined
// egf- and emf-files) or if the one of the all primitive components should be given
//
// NOTE: The component can be different is some the emf components are functions which create multiple
// primitive components (circles,polylines)
//
Geometry*
GcMulti2D::getComponent(int index, bool only_emf_components)
{
if ( only_emf_components ) {
if ( index < 0 || index > data.nofEmfComponents - 1 ) return NULL;
return data.emfComponents[index];
} else {
if ( index < 0 || index > data.nofComponents - 1 ) return NULL;
return data.components[index];
}
}
enum linDeltaType
GcMulti2D::getDeltaType()
{
return data.emfComponents[0]->getDeltaType();
}
double
GcMulti2D::getDeltaU()
{
return data.emfComponents[0]->getDeltaU();
}
void
GcMulti2D::getDiscretizationData(int& nof_components, linDeltaType*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = data.nofEmfComponents;
types = new linDeltaType[nof_components];
valuesU = new double[nof_components];
useFixedN = new bool[nof_components];
for (int i = 0; i < nof_components; i++) {
Geometry* sc = data.emfComponents[i];
types[i] = sc->getDeltaType();
valuesU[i] = sc->getDeltaU();
useFixedN[i] = sc->useFixedMeshN();
}
}
// NOTE: First simple component defines label's position!
//
void
GcMulti2D::getLabelPoint(Point3& point)
{
data.components[0]->getLabelPoint(point);
}
void
GcMulti2D::getMifTags(int& nof_tags, int*& tags)
{
nof_tags = getNofComponents();
tags = new int[nof_tags];
int index = 0;
for (int i = 0; i < data.nofComponents; i++) {
int nof_tagsc;
int* tagsc;
data.components[i]->getMifTags(nof_tagsc, tagsc);
for (int j = 0; j < nof_tagsc; j++) {
tags[index++] = tagsc[j];
}
delete[] tagsc;
tagsc = NULL;
}
}
int
GcMulti2D::getNofBoundaryPoints()
{
int count = 0;
for (int i = 0; i < data.nofComponents; i++) {
count += data.components[i]->getNofBoundaryPoints();
}
return count;
}
// NOTE: Argument flags tells if only the nof emf components (ie. components defined
// egf- and emf-files) or if the nof all primitive components shouyld be given
//
// NOTE: This number can be different if some of the emf componets are functions which create multiple
// primitive components (circles,polylines)
//
int
GcMulti2D::getNofComponents(bool only_emf_components)
{
if ( only_emf_components ) {
return data.nofEmfComponents;
} else {
return data.nofComponents;
}
}
ecif_geometryType
GcMulti2D::getType()
{
if ( data.nofComponents < 1 ) {
return ECIF_NODIM;
} else if ( data.nofComponents > 1 ) {
return ECIF_MULTI2D;
} else {
return data.components[0]->getType();
}
}
void
GcMulti2D::init()
{
data.nofEmfComponents = 0;
data.emfComponents = NULL;
data.gmtrType = ECIF_NODIM;
data.funcType = ECIF_NOFUNCTION;
data.funcArgC = 0;
data.funcArgV = NULL;
data.funcStartPoint = NULL;
data.funcEndPoint = NULL;
data.funcStartVertex = NO_INDEX;
data.funcEndVertex = NO_INDEX;
data.functionName = NULL;
data.libraryName = NULL;
}
bool
GcMulti2D::isClosedU()
{
return data.components[0]->isClosedU();
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns a structure where there is the nof intersection and
// the minimum x-coordinate for the intersections.
RayHit*
GcMulti2D::isectionsWithXdir(GcPoint* xdir_startp, bool& negative_on_left)
{
return data.components[0]->isectionsWithXdir(xdir_startp, negative_on_left);
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns nof-intersection and the corresponding x-values in the arguments
void
GcMulti2D::isectionsWithXdir(GcPoint* xdir_startp, int& nof_values , double*& values)
{
data.components[0]->isectionsWithXdir(xdir_startp, nof_values , values);
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and y-axis and which starts from point *startp* towards right.
// Returns nof-intersection and the corresponding y-values in the arguments
void
GcMulti2D::isectionsWithYdir(GcPoint* ydir_startp, int& nof_values , double*& values)
{
data.components[0]->isectionsWithYdir(ydir_startp, nof_values , values);
}
bool
GcMulti2D::isOnSameAxis(GcPoint& p1, GcPoint& p2)
{
if ( data.nofComponents < 1 || data.nofComponents > 1 ) {
return false;
} else {
return data.components[0]->isOnSameAxis(p1, p2);
}
}
ostream&
GcMulti2D::output_emf(ostream& out, short indent_size, short indent_level)
{
for (int i = 0; i < data.nofEmfComponents; i++) {
Geometry2D* pg = data.emfComponents[i];
// Simple geometry
//
if ( !pg->isMultiGeometry() ) {
pg->output_emf(out, indent_size, indent_level);
// Multi geometry
//
} else {
GcMulti2D* pg = (GcMulti2D*)data.emfComponents[i];
if ( pg->data.functionName != NULL && pg->data.libraryName != NULL ) {
pg->output_1_emf(out, indent_size, indent_level);
} else {
pg->output_n_emf(out, indent_size, indent_level);
}
}
}
return out;
}
ostream&
GcMulti2D::output_1_emf(ostream& out, short indent_size, short indent_level)
{
char* QM = "\"";
short is = indent_size;
short il = indent_level;
const char* def;
// Geometry type
def = getMatcString(data.matcTable, EMF_GEOMETRY);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_GEOMETRY, NULL, def);
else if ( data.gmtrType == ECIF_CIRCLE )
LibFront::output_scalar(out, is, il, EMF_GEOMETRY, NULL, "Circle");
else if ( data.gmtrType == ECIF_POLYLINE )
LibFront::output_scalar(out, is, il, EMF_GEOMETRY, NULL, "PolyLine");
// Argument vector
if ( data.funcArgC > 0 ) {
def = getMatcString(data.matcTable, EMF_ARGUMENTS);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_ARGUMENTS, NULL, def);
else
LibFront::output_vector(out, is, il, EMF_ARGUMENTS, NULL, data.funcArgC, data.funcArgV, false);
}
// Function definition (Func-name Library-name pair)
def = getMatcString(data.matcTable, EMF_FUNCTION);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_FUNCTION, NULL, def);
else if ( data.functionName != NULL && data.libraryName != NULL ) {
LibFront::indent(out, is, il);
out << "Function "
<< QM << data.functionName << QM
<< " "
<< QM << data.libraryName << QM
<< endl;
}
// Start,end points/vertices
if ( data.funcStartPoint != NULL ) {
def = getMatcString(data.matcTable, EMF_START_POINT);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_START_POINT, NULL, def);
else
LibFront::output_vector(out, is, il, EMF_START_POINT, NULL, 3, *data.funcStartPoint, false);
}
if ( data.funcEndPoint != NULL ) {
def = getMatcString(data.matcTable, EMF_END_POINT);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_END_POINT, NULL, def);
else
LibFront::output_vector(out, is, il, EMF_END_POINT, NULL, 3, *data.funcEndPoint, false);
}
if ( data.funcStartVertex != NO_INDEX ) {
def = getMatcString(data.matcTable, EMF_START_VERTEX);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_START_VERTEX, NULL, def);
else
LibFront::output_scalar(out, is, il, EMF_START_VERTEX, NULL, data.funcStartVertex);
}
if ( data.funcEndVertex != NO_INDEX ) {
def = getMatcString(data.matcTable, EMF_END_VERTEX);
if ( model->keepMatcDefinitions() && def != NULL )
LibFront::output_matcDef(out, indent_size, indent_level, EMF_END_VERTEX, NULL, def);
else
LibFront::output_scalar(out, is, il, EMF_END_VERTEX, NULL, data.funcEndVertex);
}
return out;
}
ostream&
GcMulti2D::output_n_emf(ostream& out, short indent_size, short indent_level)
{
for (int i = 0; i < data.nofComponents; i++) {
data.components[i]->output_emf(out, indent_size, indent_level);
}
return out;
}
ostream&
GcMulti2D::output_mif(ostream& out, const char* header, bool useGmtrMeshN)
{
for (int i = 0; i < data.nofComponents; i++) {
data.components[i]->output_mif(out, header, useGmtrMeshN);
}
return out;
}
// Calculate the point corresponding parametric values given as arguments.
// NOTE: Argument parameters are in [0,1], but circle's own parametric
// representation is between [0, 2PI]
void
GcMulti2D::param2Point(double u_p, double v_p, Point3& point)
{
data.components[0]->param2Point(u_p, v_p, point);
}
// Calculate the point corresponding paramtric values given as arguments.
// NOTE: Argument parameters are in [0,1], but circle's own parametric
// representation is between [0, 2PI]
GcPoint*
GcMulti2D::param2Point(double u_p, double v_p)
{
return data.components[0]->param2Point(u_p, v_p);
}
// Parameter value for the point (0...1)
void
GcMulti2D::point2Param(Point3* point, double& u, double& v)
{
data.components[0]->point2Param(point, u, v);
}
// Calculates the paramtetric values corresponding the argument-point.
ParamPair*
GcMulti2D::point2Param(GcPoint* point)
{
return data.components[0]->point2Param(point);
}
void
GcMulti2D::setDiscretizationData(int nof_components, linDeltaType* types, double* valuesU, double* valuesV, bool* useFixedN)
{
if ( nof_components != data.nofEmfComponents ) return;
for (int i = 0; i < nof_components; i++) {
int sub_nof_components = data.emfComponents[i]->getNofComponents();
if ( sub_nof_components > 1 ) {
for (int j = 0; j < sub_nof_components; j++) {
Geometry* sc = data.emfComponents[i]->getComponent(j);
sc->setDiscretizationData(1, &types[i], &valuesU[i], NULL, &useFixedN[i]);
}
} else {
Geometry* sc = data.emfComponents[i];
sc->setDiscretizationData(1, &types[i], &valuesU[i], NULL, &useFixedN[i]);
}
}
}
// Copy component's data to a transfer-structure for geoemtry update
//
// NOTE: By copying the data into a transfer-structure we can use the
// same create-circle/polyline functions as for original egf/emf data!
//
void
GcMulti2D::setGeometryUpdateData(ecif_ElementComponent_X& txc, ecif_Multi2D data)
{
static char func[1024];
const char* def;
const char* res;
//txc.lin_delta;
//txc.lin_delta_type;
//txc.nof_vertices;
//txc.vertex_tags;
//txc.gmtr_type;
//txc.geometry;
// Function related stuff
if ( data.funcType != ECIF_NOFUNCTION ) {
txc.isFunction = true;
switch (data.funcType) {
case ECIF_CPP: txc.isCpp = true; break;
case ECIF_F95: txc.isF95 = true; break;
case ECIF_MATC: txc.isMatc = true; break;
}
}
def = getMatcString(data.matcTable, EMF_START_POINT);
if ( def == NULL ) {
txc.startPoint = data.funcStartPoint;
} else {
res = LibFront::evalMatcString(def);
if (!LibFront::isMatcError(res)) {
txc.startPoint = create3(res);
}
}
def = getMatcString(data.matcTable, EMF_END_POINT);
if ( def == NULL ) {
txc.endPoint = data.funcEndPoint;
} else {
res = LibFront::evalMatcString(def);
if (!LibFront::isMatcError(res)) {
txc.endPoint = create3(res);
}
}
def = getMatcString(data.matcTable, EMF_START_VERTEX);
if ( def == NULL ) {
txc.startVertex = data.funcStartVertex;
} else {
res = LibFront::evalMatcString(def);
if (!LibFront::isMatcError(res)) {
txc.startVertex = atoi(res);
}
}
def = getMatcString(data.matcTable, EMF_END_VERTEX);
if ( def == NULL ) {
txc.endVertex = data.funcEndVertex;
} else {
res = LibFront::evalMatcString(def);
if (!LibFront::isMatcError(res)) {
txc.endVertex = atoi(res);
}
}
def = getMatcString(data.matcTable, EMF_FUNCTION);
if ( def == NULL ) {
update_dyna_string(txc.functionName, data.functionName);
update_dyna_string(txc.libraryName, data.libraryName);
} else {
res = LibFront::evalMatcString(def);
if (!LibFront::isMatcError(res)) {
strstream strm;
strm << res << ends;
strm >> func;
update_dyna_string(txc.functionName, func);
if (!strm.eof()) {
update_dyna_string(txc.libraryName, strm.str());
}
}
}
def = getMatcString(data.matcTable, EMF_ARGUMENTS);
if ( def == NULL ) {
txc.argc = data.funcArgC;
txc.argv = new double[txc.argc];
for (int i = 0; i < txc.argc; i++) {
txc.argv = data.funcArgV;
}
} else {
res = LibFront::evalMatcString(def);
if (!LibFront::isMatcError(res)) {
strstream strm;
strm << LibFront::trim((char*)res) << ends;
int count = 0;
double value;
while (true) {
strm >> value;
if (0 != strm.fail()) break;
count++;
}
if (count > 0) {
txc.argc = count;
txc.argv = new double[count];
strstream strm;
strm << res << ends;
int count = 0;
while (true) {
strm >> value;
if (0 != strm.fail()) break;
txc.argv[count++] = value;
}
txc.argc = count;
}
}
}
// Finally copy Matc-expressions
copyMatcValueTable(data.matcTable, txc.matcTable);
}
void
GcMulti2D::setMifTag(int& next_tag)
{
for (int i = 0; i < data.nofComponents; i++) {
data.components[i]->setMifTag(next_tag);
}
}
bool
GcMulti2D::updateData()
{
calcBoundaryPoints();
boundbox = calcBoundBox();
return true;
}
// Update geometry. Relevant when Matc-parameters have been changed!
//
bool
GcMulti2D::updateGeometry(int parent_tag, IdList& vertex_tags)
{
int i, j;
ecif_ElementComponent_X txc;
init_trx_data(txc);
int final_nof_cmpnts = 0;
Geometry2D* newGmtr = NULL;
for (i = 0; i < data.nofEmfComponents; i++) {
Geometry2D* cmp = data.emfComponents[i];
// Recreate a multi-geometry component (=functions)
// ----------------------------------
//
if ( cmp->isMultiGeometry() ) {
GcMulti2D* oldGmtr = (GcMulti2D*)cmp;
reset_trx_data(txc, ECIF_EDGE);
//init_trx_data(txc);
setGeometryUpdateData(txc, oldGmtr->data);
switch ( oldGmtr->data.gmtrType ) {
//---Function circle
//
case ECIF_CIRCLE:
if ( oldGmtr->data.funcType == ECIF_CPP )
newGmtr = createFunctionCircleC(parent_tag, txc, vertex_tags);
else if ( oldGmtr->data.funcType == ECIF_F95 )
;//newGmtr = createFunctionCircleF(parent_tag, txc, vertex_tags);
else if ( oldGmtr->data.funcType == ECIF_MATC )
newGmtr = createFunctionCircleM(parent_tag, txc, vertex_tags);
break;
//---Function polyline
//
case ECIF_POLYLINE:
if ( oldGmtr->data.funcType == ECIF_CPP )
newGmtr = createFunctionPolyLineC(parent_tag, txc, vertex_tags);
else if ( oldGmtr->data.funcType == ECIF_F95 )
;//newGmtr = createFunctionPolyLineF(parent_tag, txc, vertex_tags);
else if ( oldGmtr->data.funcType == ECIF_MATC )
newGmtr = createFunctionPolyLineM(parent_tag, txc, vertex_tags);
break;
default:
newGmtr = NULL;
break;
}
// Update simple components (and keep it, no copy is made!)
// ------------------------
//
} else {
newGmtr = cmp;
newGmtr->updateGeometry(parent_tag, vertex_tags);
}
// Error in geometry!
//
if ( newGmtr == NULL || !newGmtr->geometryIsOk() ) {
delete newGmtr;
geometryOk = false;
return false;
}
data.emfComponents[i] = newGmtr;
int ccount = newGmtr->getNofComponents();
final_nof_cmpnts += ccount;
} // Each emf-component
// Delete old simple geometry
// NOTE: old simple emfComponents should not be deleted here, because
// they were not copied above!!!
//
for (i = 0; i < data.nofComponents; i++) {
if ( data.isDeletable[i] ) {
delete data.components[i];
}
}
delete[] data.components;
delete[] data.isDeletable;
data.nofComponents = 0;
// Collect all new (simple) components into one array
//
Geometry2D** tmp = new Geometry2D*[final_nof_cmpnts];
data.isDeletable = new bool[final_nof_cmpnts];
int idx = 0;
for (i = 0; i < data.nofEmfComponents; i++) {
Geometry2D* pg = data.emfComponents[i];
// If a component is simple, take as it is
//
if ( !pg->isMultiGeometry() ) {
tmp[idx] = pg;
data.isDeletable[idx] = false;
idx++;
// If a component is a Multi2D, copy its subcomponents!
// NOTE: Sub components should have been already unpurged
// recursively!
//
} else {
for (j = 0; j < pg->getNofComponents(); j++) {
tmp[idx] = (Geometry2D*)pg->getComponent(j);
data.isDeletable[idx] = true;
idx++;
}
}
}
// These are components which all are geometry primitves (polylines,circles etc)
//
data.nofComponents = final_nof_cmpnts;
data.components = tmp;
return updateData();
}
bool
GcMulti2D::useFixedMeshN()
{
// Hack hack hack!!!
try {
return data.emfComponents[0]->useFixedMeshN();
}
catch (...) {
return false;
}
}
//*******************************
//***** GcNurbsCurve methods *****
//*******************************
// Constructor
// Emf-style call (In practice, nurbs are not acutally input from emf!)
GcNurbsCurve::GcNurbsCurve(ecif_ElementComponent_X& tx, IdList& vertex_tags)
{
nofVertices = tx.nof_vertices;
vertexTags = NULL;
if ( nofVertices > 0 ) {
vertexTags = new int[nofVertices];
for (int i = 0; i < nofVertices; i++) {
BodyElement* v = model->getVertexByTag(tx.vertex_tags[i]);
vertex_tags.push_back(v->Tag());
vertexTags[i] = v->Tag();
}
}
data.deltaType = tx.lin_delta_type;
data.delta = tx.lin_delta[0];
data.useFixedMeshN = (bool)tx.use_fixed_mesh_n;
create(tx.geometry.edge);
copyMatcValueTable(tx.matcTable, data.matcTable);
}
// Constructor
// NOTE: No vertices
GcNurbsCurve::GcNurbsCurve(ecif_EdgeGeometry_X* params, bool do_linearize)
{
nofVertices = 0;
vertexTags = NULL;
create(params, do_linearize);
}
// Constructor
// Iges/Ideas-style call
GcNurbsCurve::GcNurbsCurve(BodyElement* vertex1, BodyElement* vertex2,
ecif_EdgeGeometry_X* params, bool do_linearize)
{
nofVertices = 2;
vertexTags = new int[2];
vertexTags[0] = vertex1->Tag();
vertexTags[1] = vertex2->Tag();
create(params, do_linearize);
}
// Create nurbs curve
void
GcNurbsCurve::create(ecif_EdgeGeometry_X* params, bool do_linearize)
{
int i,j;
data.degree = params->degree;
data.nofKnots = params->nofKnots;
data.nofCpoints = params->nofCpoints;
data.knots = new double[data.nofKnots];
for (i=0; i < data.nofKnots; i++)
data.knots[i] = params->knots[i];
data.cpoints = new Point4[data.nofCpoints];
for (i=0; i < data.nofCpoints; i++) {
for(j=0; j < 4; j++)
data.cpoints[i][j] = params->cpoints[i][j];
}
// Linearization factor
deltaU = 1.0 / 36;
nofLinearizingPoints = 0;
linearizingPoints = NULL;
nofBoundaryPoints = 0;
boundaryPoints = NULL;
if (do_linearize) {
linearize();
}
boundbox = calcBoundBox();
}
// Destructor.
GcNurbsCurve::~GcNurbsCurve()
{
delete[] vertexTags;
}
// Calculates the bounding box for a nurbs curve.
BoundBox*
GcNurbsCurve::calcBoundBox()
{
int i;
// We calculate the simple min-max box from control points.
// (based on the convex hull proprety of the control polygon for nurbs)
RangeVector values;
for (i = 0; i < MAX_DIMENSION; i++) {
values[2*i] = MAX_RANGE;
values[2*i + 1] = MIN_RANGE;
}
const int DIM2 = 2; // We are in 2D !!!***!!!
for (i = 0; i < data.nofCpoints; i++) {
for (int k = 0; k < DIM2; k++) {
if (data.cpoints[i][k] < values[2*k])
values[2*k] = data.cpoints[i][k];
if (data.cpoints[i][k] > values[2*k + 1])
values[2*k + 1] = data.cpoints[i][k];
}
}
BoundBox* bbox = new BoundBox(values);
return bbox;
}
// Calculate linearized boundary
// Store result in the points-buffer
// NOTE: Buffer is allocated here, client should take care of its
// deletion!!!
//
// NOTE: Pure carbage!!!
//
void
GcNurbsCurve::calcLinearizingPoints(int& nof_points, GcPoint**& points, double delta_u)
{
nof_points = 2;
points = new GcPoint*[nof_points];
points[0] = data.start;
points[1] = data.end;
}
void
GcNurbsCurve::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
renderer->drawNurbsCrv(dmode, dstate, direction, data, elem_id);
}
void
GcNurbsCurve::getDiscretizationData(int& nof_components, linDeltaType*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = 1;
types = new enum linDeltaType[1];
types[0] = data.deltaType;
valuesU = new double[1];
valuesU[0] = data.delta;
valuesV = NULL;
useFixedN = new bool[1];
useFixedN[0] = data.useFixedMeshN;
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// (For a line-segment (*this*) nof intersections is of course 0 or 1)
RayHit*
GcNurbsCurve::isectionsWithXdir(GcPoint* xdir_startp, bool& negative_on_left)
{
// Currently nonsense! !!!***!!!
// We create a line from end-points and test with that!
GcLine line(data.start->getPoint(), data.end->getPoint());
return line.isectionsWithXdir(xdir_startp, negative_on_left);
}
void
GcNurbsCurve::linearize()
{
nofLinearizingPoints = 0;
delete[] linearizingPoints;
linearizingPoints = NULL;
calcLinearizingPoints(nofLinearizingPoints, linearizingPoints, deltaU);
model->updateMinimumEdgeSize(nofLinearizingPoints, linearizingPoints);
}
ostream&
GcNurbsCurve::output_emf(ostream& out, short indent_size, short indent_level)
{
return out;
}
// Calculate the point corresponding paramtric values given as arguments.
void
GcNurbsCurve::param2Point(double u_p, double v_p, Point3& point)
{
nurbsCurveValue(&data, u_p, point);
}
// Calculate the point corresponding paramtric values given as arguments.
GcPoint*
GcNurbsCurve::param2Point(double u_p, double v_p)
{
Point3 point;
nurbsCurveValue(&data, u_p, point);
GcPoint* p = new GcPoint(point);
return p;
}
// Calculates the paramtetric values corresponding the argument-point.
void
GcNurbsCurve::point2Param(Point3* p, double& u, double& v)
{
// Currently nearly nonsense! !!!***!!! :
// Curve is suppoused to go through first and last control-points!
// Only these "end-points" are checked!
// Other cases are suppoused to be OFF the curve!
Point4& c1 = data.cpoints[0];
Point4& c2 = data.cpoints[data.nofCpoints - 1];
Point3 p1;
Point3 p2;
for (int i = 0; i < 3; i++) {
p1[i] = c1[i];
p2[i] = c2[i];
}
//If point doesn't p1 match one of the "end-points"
//we return NULL
if ( samepoint(*p, p1) ) {
u = 0;
} else if ( samepoint(*p, p2) ) {
u = 1;
} else {
u = -1.0;
}
v = 0.0;
}
// Calculates the paramtetric values corresponding the argument-point.
ParamPair*
GcNurbsCurve::point2Param(GcPoint* p)
{
// Currently nearly nonsense! !!!***!!! :
// Curve is suppoused to go through first and last control-points!
// Only these "end-points" are checked!
// Other cases are suppoused to be OFF the curve!
double u = 0;
Point4& c1 = data.cpoints[0];
Point4& c2 = data.cpoints[data.nofCpoints - 1];
GcPoint p1(c1[0], c1[1], c1[2]);
GcPoint p2(c2[0], c2[1], c2[2]);
//If point doesn't p1 match one of the "end-points"
//we return NULL
if (*p == p1)
u = 0;
else if (*p == p2)
u = 1;
else
return NULL;
// Now we can create non-null result-object.
ParamPair* par = new ParamPair;
par->u = u;
par->v = 0;
return par;
}
// Checks if point is on the curve.
// Currently nonsense! !!!***!!!
ParamPair*
GcNurbsCurve::point2Param(GcPoint* p, int direction,
double start_u, double start_v)
{
// Currently nonsense! !!!***!!!
ParamPair* par = new ParamPair;
par->u = start_u;
par->v = start_v;
return par;
}
void
GcNurbsCurve::setDiscretizationData(int nof_components, linDeltaType* types, double* valuesU, double* valuesV, bool* useFixedN)
{
if ( nof_components = 0 ) return;
data.deltaType = types[0];
data.delta = valuesU[0];
data.useFixedMeshN = useFixedN[0];
// Update also deltaU which is always in radians
//
//setDeltaU(data.deltaType, data.delta);
}
//*******************************
//*****GcPolyLine methods *****
//*******************************
GcPolyLine::GcPolyLine(ecif_ElementComponent_X& tx, IdList& vertex_tags)
{
nofVertices = tx.nof_vertices;
vertexTags = new int[nofVertices];
int i;
for (i = 0; i < nofVertices; i++) {
vertexTags[i] = tx.vertex_tags[i];
vertex_tags.push_back(tx.vertex_tags[i]);
}
GcPoint** points = NULL;
int nof_points = tx.geometry.edge->nofDefiningPoints;
// Defining points given
// ---------------------
if ( nof_points > 0 ) {
points = new GcPoint*[nof_points];
for (i = 0; i < nof_points; i++) {
points[i] = new GcPoint(&tx.geometry.edge->definingPoints[i]);
}
// Defining vertices given
// -----------------------
} else {
nof_points = nofVertices;
points = new GcPoint*[nof_points];
for (i = 0; i < nofVertices; i++) {
BodyElement* v = model->getVertexByTag(tx.vertex_tags[i]);
vertexTags[i] = v->Tag();
vertex_tags.push_back(v->Tag());
points[i] = (GcPoint*)v->getGeometry();
}
data.hasVertexTies = true;
}
data.useFixedMeshN = (bool)tx.use_fixed_mesh_n;
create(nof_points, points);
delete[] points;
copyMatcValueTable(tx.matcTable, data.matcTable);
}
// Constructor.
GcPolyLine::GcPolyLine(int nof_points, GcPoint** gc_points)
{
nofVertices = 0;
vertexTags = NULL;
create(nof_points, gc_points);
}
GcPolyLine::GcPolyLine(int nof_vertices, BodyElement** vertices)
{
nofVertices = nof_vertices;
vertexTags = new int[nofVertices];
GcPoint** points = new GcPoint*[nofVertices];
for (int i = 0; i < nofVertices; i++) {
BodyElement* v = vertices[i];
vertexTags[i] = v->Tag();
points[i] = (GcPoint*)v->getGeometry();
}
data.hasVertexTies = true;
create(nofVertices, points);
delete[] points;
}
// Destructor.
GcPolyLine::~GcPolyLine()
{
delete[] vertexTags;
}
// Create polyline
void
GcPolyLine::create(int nof_points, GcPoint** points)
{
data.nofPoints = nof_points;
data.points = new GcPoint*[data.nofPoints];
for (int i = 0; i < data.nofPoints; i++)
data.points[i] = points[i];
nofBoundaryPoints = 0;
boundaryPoints = NULL;
updateData();
}
// Calculates bounding box for the polyline
BoundBox*
GcPolyLine::calcBoundBox()
{
RangeVector range;
BoundBox* bbox = new BoundBox();
for (int n = 1; n < data.nofPoints; n++) {
// A pair of consequtive points as a line
GcPoint* start = data.points[n - 1];
GcPoint* end = data.points[n];
range[0] = start->Pos(X);
range[1] = end->Pos(X);
range[2] = start->Pos(Y);
range[3] = end->Pos(Y);
range[4] = start->Pos(Z);
range[5] = end->Pos(Z);
bbox->extendByRange(range);
}
return bbox;
}
void
GcPolyLine::calcLinearizingPoints(int& nof_points, GcPoint**& points, double delta_u)
{
nof_points = data.nofPoints;
points = new GcPoint*[data.nofPoints];
for (int i = 0; i < data.nofPoints; i++) {
points[i] = data.points[i];
}
}
void
GcPolyLine::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
const Point3* p1;
const Point3* p2;
// Positive direction: from start to end
if ( direction == 1 ) {
for (int n = 0; n < data.nofPoints -1; n++) {
// A pair of consequtive points as a line
p1 = data.points[n]->getPoint();
p2 = data.points[n + 1]->getPoint();
renderer->drawLine(dmode, dstate, 1, p1, p2, elem_id);
}
// Negative direction: from end to start
} else {
for (int n = data.nofPoints - 1; n > 0; n--) {
// A pair of consequtive points as a line
p1 = data.points[n]->getPoint();
p2 = data.points[n - 1]->getPoint();
renderer->drawLine(dmode, dstate, 1, p1, p2, elem_id);
}
}
}
void
GcPolyLine::getDiscretizationData(int& nof_components, linDeltaType*& types, double*& valuesU, double*& valuesV, bool*& useFixedN)
{
nof_components = 1;
types = NULL;
valuesU = NULL;
valuesV = NULL;
useFixedN = new bool[1];
useFixedN[0] = data.useFixedMeshN;
}
void
GcPolyLine::getLabelPoint(Point3& point)
{
// Label in the middle of the center segment
Point3 p1;
Point3 p2;
data.points[data.nofPoints/2 - 1]->getPoint(p1);
data.points[data.nofPoints/2]->getPoint(p2);
point[0] = 0.5 * (p1[0] + p2[0]);
point[1] = 0.5 * (p1[1] + p2[1]);
point[2] = 0.0;
}
bool
GcPolyLine::getLine(int index, GcLine*& line)
{
if ( index < 0 || index > getNofLines() - 1) {
return false;
}
Point3* p1 = data.points[index]->getPoint();
Point3* p2 = data.points[index + 1]->getPoint();
line = new GcLine(p1, p2);
return true;
}
bool
GcPolyLine::isClosedU()
{
if ( data.nofPoints > 3 &&
*data.points[0] == *data.points[data.nofPoints - 1]
) {
return true;
} else {
return false;
}
}
// Counts the number of intersections with a line which is parallel to
// xy-plane and x-axis and which starts from point *startp* towards right.
// Returns a structure where there is the nof intersection and
// the minimum x-coordinate for the intersections.
RayHit*
GcPolyLine::isectionsWithXdir(GcPoint* xdir_startp, bool& negative_on_left)
{
RayHit* result = new RayHit;
int index = 0;
GcLine* line;
while (true) {
// No more lines!
if ( !getLine(index++, line) ) {
break;
}
bool neg_on_left;
RayHit* hits = line->isectionsWithXdir(xdir_startp, neg_on_left);
if ( hits != NULL ) {
result->count++;
result->points.push_back(hits->points.front());
if ( hits->min_value < result->min_value ) {
result->min_value = hits->min_value;
// NOTE: Negative on left indicator is picked
// from the "leftmost" hit, this way we can conclude the
// possible loop orientation correctly
negative_on_left = neg_on_left;
}
}
delete line;
delete hits;
}
if (result->count == 0) {
delete result;
result = NULL;
}
return result;
}
ostream&
GcPolyLine::output_emf(ostream& out, short indent_size, short indent_level)
{
LibFront::output_vector(out, indent_size, indent_level, EMF_VERTICES, NULL, nofVertices, vertexTags, false);
if ( data.useFixedMeshN ) {
LibFront::output_scalar(out, indent_size, indent_level, EMF_USE_MESH_N, NULL, 1);
}
return out;
}
// Calculate the point corresponding the paramtric values given as arguments.
// Note param value is n + u_p, where n is line index and u_p is the paramter value
// within the line
//
void
GcPolyLine::param2Point(double u_p, double v_p, Point3& point)
{
point[0] = point[1] = point[2] = 0.0;
int index = int(u_p);
GcLine* line = NULL;
getLine(index, line);
if ( line == NULL ) {
return;
}
line->param2Point(u_p - index, v_p, point);
delete line;
}
ParamPair*
GcPolyLine::point2Param(GcPoint* p)
{
GcLine* line = NULL;
int index = 0;
while (1) {
getLine(index++, line);
if ( line == NULL ) {
break;
}
ParamPair* pair = line->point2Param(p);
if ( pair != NULL ) {
return pair;
}
delete line;
}
return NULL;
}
void
GcPolyLine::setDiscretizationData(int nof_components, linDeltaType* types, double* valuesU, double* valuesV, bool* useFixedN)
{
if ( nof_components = 0 ) return;
data.useFixedMeshN = useFixedN[0];
}
bool
GcPolyLine::updateData()
{
boundbox = calcBoundBox();
return true;
}
// Update geometry. Relevant when Matc-parameters have been changed!
//
bool
GcPolyLine::updateGeometry(int parent_tag, IdList& vertex_tags)
{
return updateData();
}
//**************************************************************************
// Geometry3D methods
//**************************************************************************
//
// NOTE: Badly incomplete (3D Cad geometry not supported!)
Geometry3D::Geometry3D()
{
}
Geometry3D::~Geometry3D()
{
}
// Linearize geometry and store points in boundaryPoints array
void
Geometry3D::calcBoundaryPoints(int boundary_tag)
{
int i;
for (i = 0; i < nofBoundaryPointsU * nofBoundaryPointsV ; i++) {
delete boundaryPoints[i];
}
delete[] boundaryPoints;
nofBoundaryPointsU = 0;
nofBoundaryPointsV = 0;
boundaryPoints = NULL;
int nof_points_u;
int nof_points_v;
GcPoint** points;
double delta_u = getParamDeltaU();
double delta_v = getParamDeltaV();
calcLinearizingPoints(nof_points_u, nof_points_v, points, delta_u, delta_v);
int nof_points = 0;
nof_points = nof_points_u * nof_points_v;
if (nof_points == 0) return;
boundaryPoints = new BoundaryPoint*[nof_points];
for (i = 0; i < nof_points; i++) {
BoundaryPoint* bp = new BoundaryPoint;
boundaryPoints[i] = bp;
// Check if bp is an existing vertex!
BodyElement* v = model->getVertex(points[i]);
if ( v != NULL ) {
bp->tag = v->Tag();
bp->vertexTag = v->Tag();
}
//bp->boundaryTag = boundary_tag;
bp->point = points[i];
}
// Handle possibly closed geometry
// -------------------------------
int nof_u = nof_points_u;
int nof_v = nof_points_v;
//-Copy start points to end points if U-closed
//
if ( isClosedU() ) {
for (int i = 1; i <= nof_v; i++) {
int pos0 = (i - 1) * nof_u;
int pos1 = pos0 + nof_u - 1;
BoundaryPoint* tmp = boundaryPoints[pos1];
boundaryPoints[pos1] = boundaryPoints[pos0];
delete tmp;
}
}
//-Copy start points to end points if V-closed
//
if ( isClosedV() ) {
for (int i = 1; i <= nof_u; i++) {
int pos0 = (i - 1) * nof_v;
int pos1 = pos0 + nof_v - 1;
BoundaryPoint* tmp = boundaryPoints[pos1];
boundaryPoints[pos1] = boundaryPoints[pos0];
delete tmp;
}
}
nofBoundaryPointsU = nof_points_u;
nofBoundaryPointsV = nof_points_v;
// NOTE: Delete only the array,not the points!
//
delete[] points;
}
//**********************************
//***** GcNurbsSurface methods *****
//**********************************
//
// NOTE: Badly incomplete (3D Cad geometry not supported!)
GcNurbsSurface::GcNurbsSurface(ecif_ElementComponent_X& tx, IdList& vertex_tags)
{
nofVertices = 0;
vertexTags = NULL;
copyMatcValueTable(tx.matcTable, data.matcTable);
}
// Constructor.
GcNurbsSurface::GcNurbsSurface(ecif_FaceGeometry_X* params, bool do_linearize)
{
nofVertices = 0;
vertexTags = NULL;
create(params, do_linearize);
}
// Create surface
void
GcNurbsSurface::create(ecif_FaceGeometry_X* params, bool do_linearize)
{
int i,j;
data.isRational = params->isRational;
data.degree_u = params->degree_u;
data.nofKnots_u = params->nofKnots_u;
data.knots_u = new double[data.nofKnots_u];
for (i=0; i < data.nofKnots_u; i++)
data.knots_u[i] = params->knots_u[i];
data.degree_v = params->degree_v;
data.nofKnots_v = params->nofKnots_v;
data.knots_v = new double[data.nofKnots_v];
for (i=0; i < data.nofKnots_v; i++)
data.knots_v[i] = params->knots_v[i];
data.nofCpoints_u = params->nofCpoints_u;
data.nofCpoints_v = params->nofCpoints_v;
data.nofCpoints = params->nofCpoints;
data.cpoints = new Point4[data.nofCpoints];
for (i=0; i < data.nofCpoints; i++) {
for(j=0; j < 4; j++)
data.cpoints[i][j] = params->cpoints[i][j];
}
// Linearization factors
deltaU = 1.0 / 36;
deltaV = 1.0 / 36;
nofLinearizingPointsU = 0;
nofLinearizingPointsV = 0;
linearizingPoints = NULL;
nofBoundaryPointsU = 0;
nofBoundaryPointsV = 0;
boundaryPoints = NULL;
if (do_linearize) {
linearize();
}
boundbox = calcBoundBox();
}
// Destructor.
GcNurbsSurface::~GcNurbsSurface()
{
delete[] vertexTags;
}
BoundBox*
GcNurbsSurface::calcBoundBox()
{
int i;
// We calculate the simple min-max box from control points.
// (based on the convex hull proprety of the control polygon for nurbs)
RangeVector range;
for (i = 0; i < MAX_DIMENSION; i++) {
range[2*i] = MAX_RANGE;
range[2*i + 1] = MIN_RANGE;
}
const int DIM3 = 3; // We are in 3D !!!***!!!
for (i = 0; i < data.nofCpoints; i++) {
for (int k = 0; k < DIM3; k++) {
if (data.cpoints[i][k] < range[2*k])
range[2*k] = data.cpoints[i][k];
if (data.cpoints[i][k] > range[2*k + 1])
range[2*k + 1] = data.cpoints[i][k];
}
}
BoundBox* bbox = new BoundBox(range);
return bbox;
}
// Calculate linearized boundary
// Store result in the points-buffer
// NOTE: Buffer is allocated here, client should take care of its
// deletion!!!
// NOTE: Pure carbage!!!
void
GcNurbsSurface::calcLinearizingPoints(int& nof_points_u, int& nof_points_v, GcPoint**& points, double delta_u, double delta_v)
{
nof_points_u = 2;
nof_points_v = 2;
points = new GcPoint*[nof_points_u * nof_points_v];
for (int i = 0; i < nof_points_u * nof_points_v ; i++) {
points[i] = data.corners[i];
}
}
void
GcNurbsSurface::draw(Renderer* renderer, objectDrawingMode dmode, objectDrawingState dstate, int direction, int elem_id)
{
renderer->drawNurbsSrf(dmode, dstate, direction, data, elem_id);
}
void
GcNurbsSurface::linearize()
{
nofLinearizingPointsU = 0;
nofLinearizingPointsV = 0;
delete[] linearizingPoints;
linearizingPoints = NULL;
calcLinearizingPoints(nofLinearizingPointsU, nofLinearizingPointsV, linearizingPoints, deltaU, deltaV);
model->updateMinimumEdgeSize(nofLinearizingPointsU * nofLinearizingPointsV, linearizingPoints);
}
ostream&
GcNurbsSurface::output_emf(ostream& out, short indent_size, short indent_level)
{
return out;
}
//**************************
//*****GcPlane methods *****
//**************************
//
// NOTE: Badly incomplete (3D Cad geometry not supported!)
GcPlane::GcPlane(ecif_ElementComponent_X& tx, IdList& vertex_tags)
{
nofVertices = 0;
vertexTags = NULL;
copyMatcValueTable(tx.matcTable, data.matcTable);
}
// Constructor.
GcPlane::GcPlane(int nof_points, GcPoint** points)
{
nofVertices = 0;
vertexTags = NULL;
create(nof_points, points);
}
// Create plane
void
GcPlane::create(int nof_points, GcPoint** points)
{
if (nof_points != 4 )
return;
for (int i = 0; i < 4; i++ ) {
data.corners[i] = points[i];
}
boundbox = calcBoundBox();
}
// Destructor.
GcPlane::~GcPlane()
{
delete[] vertexTags;
}
BoundBox*
GcPlane::calcBoundBox()
{
return 0;
}
ostream&
GcPlane::output_emf(ostream& out, short indent_size, short indent_level)
{
return out;
}
// ==========================================================================
// ==========================================================================
// Geometry data structs
// ==========================================================================
// ==========================================================================
// ==========================================================================
// 2D classes
// ==========================================================================
// Struct for circle data
//
ecif_Circle::ecif_Circle() { init();}
ecif_Circle::~ecif_Circle() {
if (!hasVertexTies) {
delete start;
delete end;
}
purgeMatcValueTable(matcTable);
}
void
ecif_Circle::init() {
hasVertexTies = false;
center[0] = center[1] = center[2] = 0.0;
radius = 0.0;
isClosed = true;
start = NULL;
end = NULL;
nofDefiningPoints = 0;
definingPoints = NULL;
start_u = 0.0;
end_u = 0.0;
centerGiven = false;
radiusGiven = false;
delta = 0.0;
deltaType = LIN_DELTA_NONE;
useFixedMeshN = false;
}
// Struct for curve data
//
ecif_Curve::ecif_Curve() { init();}
ecif_Curve::~ecif_Curve() {
if (!hasVertexTies) {
for (int i = 0; i < nofPoints; i++) {
delete points[i];
}
}
delete[] points;
delete[] vertex_flags;
purgeMatcValueTable(matcTable);
}
void
ecif_Curve::init() {
hasVertexTies = false;
isClosed = true;
nofPoints = 0;
points = NULL;
vertex_flags = NULL;
}
// Struct for ellipse data
//
ecif_Ellipse::ecif_Ellipse() { init();}
ecif_Ellipse::~ecif_Ellipse() {
if (!hasVertexTies) {
delete start;
delete end;
}
purgeMatcValueTable(matcTable);
}
void
ecif_Ellipse::init() {
hasVertexTies = false;
center[0] = center[1] = center[2] = 0.0;
radius1 = 0.0;
radius2 = 0.0;
isClosed = true;
start = NULL;
end = NULL;
}
// Struct for hyperbola data
//
ecif_Hyperbola::ecif_Hyperbola() { init();}
ecif_Hyperbola::~ecif_Hyperbola() {
if (!hasVertexTies) {
delete start;
delete end;
}
purgeMatcValueTable(matcTable);
}
void
ecif_Hyperbola::init() {
hasVertexTies = false;
center[0] = center[1] = center[2] = 0.0;
direction[0] = direction[1] = direction[2] = 0.0;
radius1 = 0.0;
radius2 = 0.0;
start = NULL;
end = NULL;
}
// Struct for line data
//
ecif_Line::ecif_Line() { init();}
ecif_Line::~ecif_Line() {
if (!hasVertexTies) {
delete start;
delete end;
}
purgeMatcValueTable(matcTable);
}
void
ecif_Line::init() {
hasVertexTies = false;
onSymmAxis = 0;
normal[0] = normal[1] = normal[2] = 0.0;
length = 0.0;
start = NULL;
end = NULL;
dir = NULL;
useFixedMeshN = false;
}
// Struct for multi-geometry data
//
ecif_Multi2D::ecif_Multi2D() { init();}
ecif_Multi2D::~ecif_Multi2D() {
delete[] emfComponents;
delete[] components;
delete[] functionName;
delete[] libraryName;
purgeMatcValueTable(matcTable);
}
void
ecif_Multi2D::init() {
hasVertexTies = false;
nofEmfComponents = 0;
emfComponents = NULL;
nofComponents = 0;
isDeletable = NULL;
components = NULL;
gmtrType = ECIF_NODIM;
funcType = ECIF_NOFUNCTION;
funcArgC = 0;
funcArgV = NULL;
funcStartPoint = NULL;
funcEndPoint = NULL;
funcStartVertex = NO_INDEX;
funcEndVertex = NO_INDEX;
functionName = NULL;
libraryName = NULL;
// NOTE: These are valid when there is only one emf component!
deltaType = LIN_DELTA_NONE;
delta = 0.0;
useFixedMeshN = false;
}
// Struct for nurbs curve data
ecif_NurbsCurve::ecif_NurbsCurve() { init();}
ecif_NurbsCurve::~ecif_NurbsCurve() {
if (!hasVertexTies) {
delete start;
delete end;
}
delete[] knots;
delete[] cpoints;
purgeMatcValueTable(matcTable);
}
void
ecif_NurbsCurve::init() {
hasVertexTies = false;
isRational = 0;
degree = 0;
nofKnots = 0;
nofCpoints = 0;
knots = NULL;
cpoints = NULL;
start = NULL;
end = NULL;
useFixedMeshN = false;
}
// Struct for parabola data
//
ecif_Parabola::ecif_Parabola() { init();}
ecif_Parabola::~ecif_Parabola() {
if (!hasVertexTies) {
delete start;
delete end;
}
purgeMatcValueTable(matcTable);
}
void
ecif_Parabola::init() {
hasVertexTies = false;
apex[0] = apex[1] = apex[2] = 0.0;
direction[0] = direction[1] = direction[2] = 0.0;
focalLength = 0.0;
start = NULL;
end = NULL;
}
// Struct for polyline data
//
ecif_PolyLine::ecif_PolyLine() { init();}
ecif_PolyLine::~ecif_PolyLine() {
if (!hasVertexTies) {
for (int i = 0; i < nofPoints; i++) {
delete points[i];
}
}
delete[] points;
purgeMatcValueTable(matcTable);
}
void
ecif_PolyLine::init() {
hasVertexTies = false;
nofPoints = 0;
points = NULL;
useFixedMeshN = false;
}
// Struct for spline curve data
//
ecif_SplineCurve::ecif_SplineCurve() { init();}
ecif_SplineCurve::~ecif_SplineCurve() {
if (!hasVertexTies) {
delete start;
delete end;
}
delete[] cpoints;
purgeMatcValueTable(matcTable);
}
void
ecif_SplineCurve::init() {
hasVertexTies = false;
degree = 0;
nofCpoints = 0;
cpoints = NULL;
start = NULL;
end = NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1