Commit f96f2d4b authored by hrchilds's avatar hrchilds
Browse files

Update from May 28, 2004

git-svn-id: http://visit.ilight.com/svn/visit/trunk/src@251 18c085ea-50e0-402c-830e-de6fd14e8384
parent 3fcd257e
......@@ -138,6 +138,25 @@ otool -hv libfoo.dylib
# Print all of the library dependencies
otool -hvL libfoo.dylib
==============================================================================
Support libraries
==============================================================================
Most of the instructions in this document are for building the various support
libraries that VisIt depends on as prebound dynamic libraries. Few of the
libraries that VisIt uses actually have support in their make system for
producing prebound dynamic libraries so it is imperative that you follow the
directions or VisIt will not be prebound. Remember that you can always use the
otool command to check whether a library or executable is prebound.
Before building VisIt or any of its support libraries, you need to create a
"visit" directory in which the support libraries will be installed. We also create
file that contains the path so we can use that in some of the instructions
later on.
mkdir visit
echo `pwd`/visit > visitpath
==============================================================================
Building Qt as a set of prebound dynamic libraries
==============================================================================
......@@ -522,6 +541,7 @@ Building HDF5 as a prebound dynamic library
===============================================================================
tar zxvf hdf5-1.6.0.tar.gz
cd hdf5-1.6.0
env CFLAGS="-O2 -fPIC" ./configure
make
......@@ -570,9 +590,30 @@ offset = offset + (0x1000 - offset % 0x1000)
# Next offset
offset = 0x2562a000
VisIt uses GNU's autoconf system to provide platform independence when
building VisIt in a UNIX environment. Autoconf creates a script called
configure that tests your system for various libraries and programs required
to build VisIt. Follow the directions listed below to build VisIt.
More information about building VisIt follows after that.
#
# Configure VisIt
#
gunzip visit040517.tar.gz
tar xf visit040517.tar
cd visit040517/config-site
echo VISITHOME=`cat ../../visitpath` > `hostname`.conf
cat Template.conf >> `hostname`.conf
cd ..
env CXXFLAGS="-O2" ./configure
#
# If VisIt failed to configure properly, check the contents of the
# `hostname`.conf file to make sure that it points to the libraries that
# you build. You can look at whitestar.conf, which is a configuration file
# for another MacOS X computer, if you want an example file that works.
#
# Change the Silo optimization level.
The Silo database reader plugin fails to build on MacOS X with GCC3.3 because
it runs out of memory with the default -O2 optimization flag.
......
......@@ -8,96 +8,57 @@
# Programmer: Brad Whitlock
# Date: Fri Aug 29 13:46:10 PST 2003
#
# Modifications:
# Brad Whitlock, Thu May 27 12:10:02 PDT 2004
# I rewrote it so it uses code that is more similar to visit-bin-dist.
#
###############################################################################
set VISITTOP = `pwd`
set VISITBIN = "$VISITTOP/bin"
set VISITLIB = "$VISITTOP/lib"
set VISITINCLUDE = "$VISITTOP/include"
set VISITICONDIR = "$VISITTOP/common/icons"
if -e $VISITBIN then
# This is kind of a hack, but create the top level Frameworks directory
# because the visit script needs it to run xml2makefile without having
# to set the DYLD_LIBRARY_PATH beforehand. Without this step, configure
# fails when trying to create plugin Makefiles.
if -e Frameworks then
rm -rf Frameworks
endif
mkdir Frameworks
cp lib/libqt.dylib Frameworks/libqt.3.dylib
# Get the version and cd into the bin directory.
set VERSION = `cat VERSION`
cd $VISITBIN
##
## Create the GUI bundle.
## Create the various application bundles.
##
if -e gui.app then
rm -f gui.app/Contents/{bin,lib}
rm -rf gui.app
endif
mkdir gui.app
mkdir gui.app/Contents
mkdir gui.app/Contents/MacOS
ln -s $VISITBIN gui.app/Contents/bin
ln -s $VISITLIB gui.app/Contents/lib
ln -s $VISITBIN/gui gui.app/Contents/MacOS/gui
ln -s $VISITBIN/visit gui.app/Contents/MacOS/visit
sed "s/PROGRAMNAME/VisIt/g" $VISITINCLUDE/Info.plist | sed "s/VERSION/$VERSION/g" > gui.app/Contents/Info.plist
echo "APPL????" > gui.app/Contents/PkgInfo
set graphicalApps="gui viewer silex xmledit"
set menuNames = ("VisIt" "VisIt Viewer" "Silex" "XmlEdit")
set creatorCodes = ("VISI" "VISV" "SILX" "XEDT")
set plist = ("Info.plist" "ViewerInfo.plist" "Info.plist" "Info.plist")
# change these when there are more icons
set iconFiles = ("VisItIcon" "VisItIcon" "VisItIcon" "VisItIcon")
@ i = 1
set pwd = `pwd`
foreach app ($graphicalApps)
echo "Making application bundle for $app"
##
## Create the viewer bundle.
##
if -e viewer.app then
rm -f viewer.app/Contents/{bin,lib}
rm -rf viewer.app
endif
mkdir viewer.app
mkdir viewer.app/Contents
mkdir viewer.app/Contents/MacOS
ln -s $VISITBIN viewer.app/Contents/bin
ln -s $VISITLIB viewer.app/Contents/lib
ln -s $VISITBIN/viewer viewer.app/Contents/MacOS/viewer
ln -s $VISITBIN/visit viewer.app/Contents/MacOS/visit
sed "s/PROGRAMNAME/VisIt Viewer/g" $VISITINCLUDE/Info.plist | sed "s/VERSION/$VERSION/g" > viewer.app/Contents/Info.plist
echo "APPL????" > viewer.app/Contents/PkgInfo
if -e $app.app then
rm -f $app.app/Contents/{bin,lib}
rm -rf $app.app
endif
##
## Create the silex bundle.
##
if -e silex.app then
rm -f silex.app/Contents/{bin,lib}
rm -rf silex.app
endif
mkdir silex.app
mkdir silex.app/Contents
mkdir silex.app/Contents/MacOS
ln -s $VISITBIN silex.app/Contents/bin
ln -s $VISITLIB silex.app/Contents/lib
ln -s $VISITBIN/silex silex.app/Contents/MacOS/silex
ln -s $VISITBIN/visit silex.app/Contents/MacOS/visit
sed "s/PROGRAMNAME/Silex/g" $VISITINCLUDE/Info.plist | sed "s/VERSION/$VERSION/g" > silex.app/Contents/Info.plist
echo "APPL????" > silex.app/Contents/PkgInfo
##
## Create the xmledit bundle.
##
if -e xmledit.app then
rm -f xmledit.app/Contents/{bin,lib}
rm -rf xmledit.app
endif
mkdir xmledit.app
mkdir xmledit.app/Contents
mkdir xmledit.app/Contents/MacOS
ln -s $VISITBIN xmledit.app/Contents/bin
ln -s $VISITLIB xmledit.app/Contents/lib
ln -s $VISITBIN/xmledit xmledit.app/Contents/MacOS/xmledit
ln -s $VISITBIN/visit xmledit.app/Contents/MacOS/visit
sed "s/PROGRAMNAME/XMLEdit/g" $VISITINCLUDE/Info.plist | sed "s/VERSION/$VERSION/g" > xmledit.app/Contents/Info.plist
echo "APPL????" > xmledit.app/Contents/PkgInfo
mkdir $app.app
mkdir $app.app/Contents
mkdir $app.app/Contents/MacOS
mkdir $app.app/Contents/Resources
cd $app.app/Contents
ln -s ../../../lib lib
cd MacOS
ln -s ../../../$app $app
ln -s ../../../../../../bin/visit visit
cd $pwd
cp $VISITICONDIR/$iconFiles[$i].icns $app.app/Contents/Resources
sed "s/PROGRAMNAME/$menuNames[$i]/g" $VISITINCLUDE/$plist[$i] | sed "s/VERSION/$VERSION/g" | sed "s/CREATORCODE/$creatorCodes[$i]/g" | sed "s/ICONFILE/$iconFiles[$i]/g" > $app.app/Contents/Info.plist
echo "APPL$creatorCodes[$i]" > $app.app/Contents/PkgInfo
@ i++
end
else
@echo "The makebundles script must be run from the top level VisIt directory."
endif
......@@ -173,6 +173,10 @@
# I changed it so we copy the Qt/Mac header files since we're now using
# Qt/Mac free edition.
#
# Brad Whitlock, Thu May 27 11:58:01 PDT 2004
# I added support for using different Info.plist files so the viewer gets
# its own plist file that prevents it from getting its own menu.
#
#------------------------------------------------------------------------------
set DataFiles = "TRUE"
......@@ -591,6 +595,7 @@ if("$os" == "darwin") then
set graphicalApps="gui viewer silex xmledit"
set menuNames = ("VisIt" "VisIt Viewer" "Silex" "XmlEdit")
set creatorCodes = ("VISI" "VISV" "SILX" "XEDT")
set plist = ("Info.plist" "ViewerInfo.plist" "Info.plist" "Info.plist")
# change these when there are more icons
set iconFiles = ("VisItIcon" "VisItIcon" "VisItIcon" "VisItIcon")
@ i = 1
......@@ -608,7 +613,7 @@ if("$os" == "darwin") then
ln -s ../../../../../../bin/visit visit
cd $pwd
cp $VisItDir/common/icons/$iconFiles[$i].icns $bindir/$app.app/Contents/Resources
sed "s/PROGRAMNAME/$menuNames[$i]/g" $VisItDir/include/Info.plist | sed "s/VERSION/$Version/g" | sed "s/CREATORCODE/$creatorCodes[$i]/g" | sed "s/ICONFILE/$iconFiles[$i]/g" > $bindir/$app.app/Contents/Info.plist
sed "s/PROGRAMNAME/$menuNames[$i]/g" $VisItDir/include/$plist[$i] | sed "s/VERSION/$Version/g" | sed "s/CREATORCODE/$creatorCodes[$i]/g" | sed "s/ICONFILE/$iconFiles[$i]/g" > $bindir/$app.app/Contents/Info.plist
echo "APPL$creatorCodes[$i]" > $bindir/$app.app/Contents/PkgInfo
@ i++
end
......
......@@ -33,6 +33,9 @@
# I changed the script so it copies the lite PDB header files into the new
# include directory before the old directory gets blown away.
#
# Brad Whitlock, Thu May 27 14:26:41 PST 2004
# Changed to account for the new location of winutil.
#
#------------------------------------------------------------------------------
if(`pwd` != "/data_vobs/VisIt") then
......@@ -91,7 +94,7 @@ rm -rf $VISITSRC/include/visit
#
# Move a bunch of the core header files to the new visit directory
#
foreach srcdir (common components gui viewer engine mdserver launcher visitpy visit_vtk vtkqt)
foreach srcdir (common components gui viewer engine mdserver launcher visitpy visit_vtk vtkqt winutil)
foreach srcfile (`find $VISITSRC/$srcdir -name "*.h"`)
mv $srcfile include/VisIt
end
......
......@@ -22,6 +22,8 @@ typedef void (*ErrorFunction)(void *, const char *);
// Programmer: "Hank Childs" (Added documentation)
// Creation: August 8, 2003 (Added documentation)
//
// Modifications:
//
// ****************************************************************************
namespace Init
......@@ -33,7 +35,7 @@ namespace Init
MISC_API bool IsComponent(const char *);
MISC_API void ComponentIssueError(const char *);
MISC_API void ComponentRegisterErrorFunction(ErrorFunction, void *);
MISC_API const char *const CatchAllMeshName = "for active plot";
const char *const CatchAllMeshName = "for active plot";
}
#endif
......
......@@ -128,6 +128,9 @@ avtDatabaseFactory::SetDefaultFormat(const char *f)
// Hank Childs, Sun May 9 11:41:45 PDT 2004
// Use the user-settable default format, rather than a hard-coded "Silo".
//
// Brad Whitlock, Thu May 27 18:12:45 PST 2004
// I fixed a bug that I introduced into the Windows extension comparison.
//
// ****************************************************************************
avtDatabase *
......@@ -223,7 +226,7 @@ avtDatabaseFactory::FileList(const char * const * filelist, int filelistN,
//
vector<string> extensions = info->GetDefaultExtensions();
int nextensions = extensions.size();
for (j=0; j<nextensions; j++)
for (j=0; j<nextensions && !foundMatch; j++)
{
string ext = extensions[j];
if (ext[0] != '.')
......
......@@ -5838,6 +5838,10 @@ avtGenericDatabase::GetDomainName(const std::string &varName, const int ts,
// Programmer: Kathleen Bonnell
// Creation: May 25, 2004
//
// Modifications:
// Kathleen Bonnell, Thu May 27 17:46:25 PDT 2004
// Take ghost zones into account.
//
// ****************************************************************************
bool
......@@ -5849,7 +5853,29 @@ avtGenericDatabase::QueryZoneCenter(const string &varName, const int dom,
bool rv = false;
if (ds)
{
vtkCell *cell = ds->GetCell(zoneId);
int zone = zoneId;
if (ds->GetDataObjectType() == VTK_RECTILINEAR_GRID ||
ds->GetDataObjectType() == VTK_STRUCTURED_GRID)
{
if (ds->GetCellData()->GetArray("vtkGhostLevels") != NULL)
{
int dims[3], ijk[3] = {0, 0, 0};
vtkVisItUtility::GetDimensions(ds, dims);
vtkVisItUtility::GetLogicalIndices(ds, true, zoneId, ijk, false, false);
vtkIntArray *realDims =
(vtkIntArray*)ds->GetFieldData()->GetArray("avtRealDims");
if (realDims != NULL)
{
ijk[0] += realDims->GetValue(0);
ijk[1] += realDims->GetValue(2);
ijk[2] += realDims->GetValue(4);
}
zone = ijk[0] +
ijk[1] * (dims[0]-1) +
ijk[2] * (dims[0]-1) * (dims[1]-1);
}
}
vtkCell *cell = ds->GetCell(zone);
float parametricCenter[3];
float weights[28];
int subId = cell->GetParametricCenter(parametricCenter);
......
......@@ -6,6 +6,7 @@
#define EXPR_PIPELINE_STATE_H
#include <avtDataObject.h>
#include <expression_exports.h>
class avtExpressionFilter;
......@@ -24,7 +25,7 @@ class avtExpressionFilter;
//
// ****************************************************************************
class ExprPipelineState
class EXPRESSION_API ExprPipelineState
{
public:
ExprPipelineState();
......
......@@ -73,15 +73,48 @@ VisWinLighting::~VisWinLighting()
// Programmer: Kathleen Bonnell
// Creation: August 27, 2002
//
// Modifications:
// Eric Brugger, Tue May 25 14:03:06 PDT 2004
// Modify the routine to set the light position so that the light source
// direction vtk passes to OpenGL is normalized.
//
// ****************************************************************************
void
VisWinLighting::InitDefaultLight()
{
//
// Get the camera's distance from the focal point.
//
vtkCamera *cam = mediator.GetCanvas()->GetActiveCamera();
float cpos[3], cfoc[3], proj[3], projLen = 0.;
cam->GetPosition(cpos);
cam->GetFocalPoint(cfoc);
proj[0] = cpos[0] - cfoc[0];
proj[1] = cpos[1] - cfoc[1];
proj[2] = cpos[2] - cfoc[2];
int i;
for (i = 0; i < 3; i++)
{
projLen += (proj[i] * proj[i]);
}
//
// Position the light so that vtk passes a unit vector for
// the light direction to OpenGL. The projected length is
// actually the square of the distance, but that is what we
// want, so there is no use taking the square root, only to
// to square it again.
//
float pos[3];
pos[0] = cfoc[0] + proj[0] / projLen;
pos[1] = cfoc[0] + proj[1] / projLen;
pos[2] = cfoc[0] + proj[2] / projLen;
lights[0]->SetLightTypeToCameraLight();
lights[0]->SetFocalPoint(cam->GetFocalPoint());
lights[0]->SetPosition(cam->GetPosition());
lights[0]->SetFocalPoint(cfoc);
lights[0]->SetPosition(pos);
lights[0]->SetColor(1., 1., 1.);
lights[0]->SetIntensity(1.);
lights[0]->SwitchOn();
......@@ -349,6 +382,10 @@ VisWinLighting::GetNumLightsEnabled()
// Distinguish between 3D and 2D actions for updating the light positions.
// For 3D lights, update the focal point as well.
//
// Eric Brugger, Tue May 25 14:03:06 PDT 2004
// Modify the routine to set the light position so that the light source
// direction vtk passes to OpenGL is normalized.
//
// ****************************************************************************
void
......@@ -379,17 +416,17 @@ VisWinLighting::UpdateLightPositions()
// from the light's position to the focal point. We need
// to use the inverse vector in determing the position
// in world coordinates. We want to position the light
// the same distance from the focal point as the camera,
// along the (inverse) direction vector.
// so that vtk passes a unit vector for the light direction
// along the (inverse) direction vector to OpenGL.
//
float pos[3];
avtLight aLight;
for (i = 0; i < MAX_LIGHTS ; i++)
{
aLight = avtlights.Light(i);
pos[0] = cfoc[0] - projLen * aLight.direction[0];
pos[1] = cfoc[1] - projLen * aLight.direction[1];
pos[2] = cfoc[2] - projLen * aLight.direction[2];
pos[0] = cfoc[0] - aLight.direction[0] / projLen;
pos[1] = cfoc[1] - aLight.direction[1] / projLen;
pos[2] = cfoc[2] - aLight.direction[2] / projLen;
lights[i]->SetPosition(pos);
lights[i]->SetFocalPoint(cfoc);
}
......
No preview for this file type
......@@ -10,7 +10,7 @@ package llnl.visit;
// Notes: Autogenerated by xml2java.
//
// Programmer: xml2java
// Creation: Wed May 12 07:29:36 PDT 2004
// Creation: Fri May 28 09:18:54 PDT 2004
//
// Modifications:
//
......
......@@ -2483,9 +2483,9 @@ ViewerQueryManager::PointQuery(const string &qName, const double *pt,
ppi.validPick = true;
if (!doTime)
Pick(&ppi, arg1, arg2);
Pick(&ppi, arg2, arg1);
else
PickThroughTime(&ppi, arg1, arg2);
PickThroughTime(&ppi, arg2, arg1);
win->SetInteractionMode(imode);
}
......
......@@ -19,7 +19,7 @@
// A factory that will allow VisIt to override any vtkObject
// with a sub-class of that object.
//
class VISIT_VTK_LIGHT_API vtkVisItGraphicsFactory : public vtkObjectFactory
class vtkVisItGraphicsFactory : public vtkObjectFactory
{
public:
vtkVisItGraphicsFactory();
......
......@@ -25,6 +25,7 @@
#define __vtkVisItMesaPolyDataMapper_h
#include "vtkPolyDataMapper.h"
#include <visit_vtk_exports.h>
class vtkProperty;
class vtkRenderWindow;
......@@ -39,7 +40,7 @@ class vtkTimerLog;
//
// ****************************************************************************
class VTK_RENDERING_EXPORT vtkVisItMesaPolyDataMapper : public vtkPolyDataMapper
class VISIT_VTK_API vtkVisItMesaPolyDataMapper : public vtkPolyDataMapper
{
public:
static vtkVisItMesaPolyDataMapper *New();
......
......@@ -1841,7 +1841,6 @@ static void vtkOpenGLDrawCS3(vtkCellArray *aPrim, GLenum aGlFunction,
vtkIdType *pts = 0;
vtkIdType npts = 0;
int count = 0;
float polyNorm[3];
GLenum previousGlFunction=GL_INVALID_VALUE;
......
......@@ -25,6 +25,7 @@
#define __vtkVisItOpenGLPolyDataMapper_h
#include "vtkPolyDataMapper.h"
#include <visit_vtk_exports.h>
class vtkProperty;
class vtkRenderWindow;
......@@ -38,7 +39,7 @@ class vtkOpenGLRenderer;
//
// ****************************************************************************
class VTK_RENDERING_EXPORT vtkVisItOpenGLPolyDataMapper : public vtkPolyDataMapper
class VISIT_VTK_API vtkVisItOpenGLPolyDataMapper : public vtkPolyDataMapper
{
public:
static vtkVisItOpenGLPolyDataMapper *New();
......
......@@ -83,6 +83,12 @@ vtkVisItPolyDataNormals::Execute()
// Kathleen Bonnell, Fri Aug 22 16:48:20 PDT 2003
// Pass along Verts and Lines.
//
// Jeremy Meredith, Fri May 28 12:30:41 PDT 2004
// Renormalize the vectors here because VTK can't do it without
// under/overflow on small/big vectors. Use double precision for
// critical math operations. Added note of concern about using
// VTK's normal calculation at all.
//
// ****************************************************************************
void
vtkVisItPolyDataNormals::ExecutePointWithoutSplitting()
......@@ -163,7 +169,10 @@ vtkVisItPolyDataNormals::ExecutePointWithoutSplitting()
//
// Technically, we can use the first three vertices only,
// (i.e. vtkTriangle::ComputeNormal), but this is not a big
// hit, and it accomodates for degenerate quads.
// hit, and it accomodates for degenerate quads. Note -- this
// will probably fail for very large/small polygons because of
// over/underflow. If so, we need to switch to double precision
// math and avoid using the VTK code.
//
float normal[3];
vtkPolygon::ComputeNormal(inPts, nVerts, connPtr, normal);
......@@ -183,7 +192,13 @@ vtkVisItPolyDataNormals::ExecutePointWithoutSplitting()
// Renormalize the normals; ther've only been accumulated so far
for (i = 0 ; i < nPoints ; i++)
{
vtkMath::Normalize(&newNormalPtr[i*3]);
double nx = newNormalPtr[i*3+0];
double ny = newNormalPtr[i*3+1];
double nz = newNormalPtr[i*3+2];
double length = sqrt(nx*nx + ny*ny + nz*nz);
newNormalPtr[i*3+0] = nx/length;
newNormalPtr[i*3+1] = ny/length;
newNormalPtr[i*3+2] = nz/length;
}
outPD->SetNormals(newNormals);
......@@ -326,6 +341,9 @@ class NormalList
// Hank Childs, Fri Jan 30 09:35:46 PST 2004
// Use pointer arithmetic to avoid VTK calls.
//
// Jeremy Meredith, Fri May 28 09:46:14 PDT 2004
// Use double precision math in critical sections.
//
// ****************************************************************************
void
vtkVisItPolyDataNormals::ExecutePointWithSplitting()
......@@ -383,7 +401,7 @@ vtkVisItPolyDataNormals::ExecutePointWithSplitting()
// Technically, we can always use only the first three vertices, but
// it is not a big hit to do the quads better, and it accomodates for
// degenerate quads directly. The code is the same algorithm as
// vtkPolygon::ComputeNormal, but without the built-in renormalization.
// vtkPolygon::ComputeNormal, but changed to make it work better.
//
float v0[3], v1[3], v2[3];
float normal[3] = {0, 0, 0};
......@@ -400,7 +418,7 @@ vtkVisItPolyDataNormals::ExecutePointWithSplitting()
inPts->GetPoint(cell[0],v1);
inPts->GetPoint(cell[1],v2);
float ax, ay, az, bx, by, bz;
double ax, ay, az, bx, by, bz;
for (j = 0 ; j < nVerts ; j++)
{
v0[0] = v1[0]; v0[1] = v1[1]; v0[2] = v1[2];
......@@ -410,9 +428,9 @@ vtkVisItPolyDataNormals::ExecutePointWithSplitting()
ax = v2[0] - v1[0]; ay = v2[1] - v1[1]; az = v2[2] - v1[2];
bx = v0[0] - v1[0]; by = v0[1] - v1[1]; bz = v0[2] - v1[2];
normal[0] += (ay * bz - az * by);
normal[1] += (az * bx - ax * bz);
normal[2] += (ax * by - ay * bx);
normal[0] += float(ay * bz - az * by);
normal[1] += float(az * bx - ax * bz);
normal[2] += float(ax * by - ay * bx);
}
normal[0] /= nVerts;
normal[1] /= nVerts;
......@@ -420,16 +438,17 @@ vtkVisItPolyDataNormals::ExecutePointWithSplitting()
}
// Calculate the length, and throw out degenerate cases
float length = sqrt(normal[0]*normal[0] +
normal[1]*normal[1] +
normal[2]*normal[2]);
double nx = normal[0];
double ny = normal[1];
double nz = normal[2];
double length = sqrt(nx*nx + ny*ny + nz*nz);
if (length == 0) continue;
// Store the normalized version separately
float nnormal[3] = {normal[0]/length,
normal[1]/length,
normal[2]/length};
float nnormal[3] = {nx/length,
ny/length,
nz/length};
// Loop over all points of the cell, deciding if we need
// to split it or can merge with an old one. Use the feature
......@@ -474,12 +493,15 @@ vtkVisItPolyDataNormals::ExecutePointWithSplitting()
n[1] += normal[1];
n[2] += normal[2];
float newlength = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
double nx = n[0];
double ny = n[1]