DGtal  0.9.3
Functions
viewDualSurface.cpp File Reference
#include <iostream>
#include <algorithm>
#include "DGtal/base/Common.h"
#include "DGtal/helpers/StdDefs.h"
#include "DGtal/topology/helpers/Surfaces.h"
#include "ConfigExamples.h"
#include "DGtal/io/viewers/Viewer3D.h"
Include dependency graph for viewDualSurface.cpp:

Go to the source code of this file.

Functions

template<typename Vector >
Vector wedge (const Vector &v1, const Vector &v2)
 
template<typename Vector >
void naiveConvexHull (std::vector< std::vector< unsigned int > > &indices, const std::vector< Vector > &points, bool left_handed)
 
double rescale (double x)
 
template<typename Viewer , typename Vector >
void viewPolygons (Viewer &viewer, const DGtal::Color &color, const std::vector< std::vector< unsigned int > > &indices, const std::vector< Vector > &points)
 
template<typename Vector >
unsigned int dim (const Vector &z)
 
template<typename Vector >
unsigned int openDim (const Vector &z)
 
template<typename Vector >
Vector lower (const Vector &z, unsigned int k)
 
template<typename Vector >
Vector upper (const Vector &z, unsigned int k)
 
template<typename Vector >
unsigned int nbLighted (std::map< Vector, bool > &f, const Vector &z)
 
template<typename Vector >
bool lightBetween (std::map< Vector, bool > &f, const Vector &z)
 
template<typename Vector >
bool lightMax (std::map< Vector, bool > &f, const Vector &z)
 
template<typename Vector >
bool lightMinMax (std::map< Vector, bool > &f, const Vector &z)
 
template<typename Vector >
bool lightMaxMin (std::map< Vector, bool > &f, const Vector &z)
 
template<typename Vector >
bool lightEpsilon (std::map< Vector, bool > &f, const Vector &z, unsigned int epsilon)
 
template<typename Vector >
void fillCfg (std::map< Vector, bool > &f, const Vector &z, unsigned int cfg)
 
template<typename Vector >
void localDualVolume (std::vector< Vector > &points, std::map< Vector, bool > &f, const Vector &z)
 
int main (int argc, char **argv)
 

Detailed Description

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Date
2011/03/25

An example file named viewDualSurface.

This file is part of the DGtal library.

Definition in file viewDualSurface.cpp.

Function Documentation

◆ dim()

template<typename Vector >
unsigned int dim ( const Vector z)
Examples:
dec/exampleDiscreteExteriorCalculusSolve.cpp, geometry/volumes/distance/distancetransform2D.cpp, geometry/volumes/distance/distancetransform3D.cpp, and io/viewDualSurface.cpp.

Definition at line 182 of file viewDualSurface.cpp.

Referenced by DGtal::functors::BasicDomainSubSampler< TDomain, TInteger, TValue >::BasicDomainSubSampler(), checkPowerMap(), checkVoronoi(), DGtal::SeparableMetricAdapter< TMetric >::closest(), fillCfg(), DGtal::PowerMap< TWeightImage, TPSeparableMetric, TImageContainer >::isPeriodic(), DGtal::VoronoiMap< TSpace, TPointPredicate, TSeparableMetric, TImageContainer >::isPeriodic(), lightBetween(), lightEpsilon(), lightMax(), lightMaxMin(), lightMinMax(), nbLighted(), std::hash< DGtal::KhalimskyCell< dim, TInteger > >::operator()(), std::hash< DGtal::SignedKhalimskyCell< dim, TInteger > >::operator()(), boost::hash< DGtal::KhalimskyCell< dim, TInteger > >::operator()(), DGtal::functors::BasicDomainSubSampler< TDomain, TInteger, TValue >::operator()(), DGtal::functors::FlipDomainAxis< TDomain >::operator()(), DGtal::InexactPredicateLpSeparableMetric< TSpace, TValue >::operator=(), DGtal::ExactPredicateLpPowerSeparableMetric< TSpace, p, TPromoted >::operator=(), DGtal::ExactPredicateLpSeparableMetric< TSpace, p, TRawValue >::operator=(), DGtal::experimental::ChamferNorm2D< TSpace >::operator=(), DGtal::ExactPredicateLpSeparableMetric< TSpace, 2, TRawValue >::operator=(), DGtal::ExactPredicateLpPowerSeparableMetric< TSpace, 2, TPromoted >::operator=(), randomSeeds(), DGtal::PointVector< dim, Integer >::rows(), runATest(), test_manual_operators_2d(), testCompareExactBruteForce(), testCompareExactInexact(), testCompareInexactBruteForce(), and testComparison().

183 {
184  unsigned int d = 0;
185  for ( unsigned int i = 0; i < Vector::dimension; ++i )
186  if ( ( z[ i ] % 2 ) == 1 ) ++d;
187  return d;
188 }

◆ fillCfg()

template<typename Vector >
void fillCfg ( std::map< Vector, bool > &  f,
const Vector z,
unsigned int  cfg 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 345 of file viewDualSurface.cpp.

References dim(), lower(), openDim(), and upper().

Referenced by main().

348 {
349  unsigned int d = dim( z );
350  if ( d == 0 )
351  {
352  f[ z ] = (cfg == 1);
353  //std::cerr << "f[" << z << "] = " << f[ z ] << std::endl;
354  }
355  else
356  {
357  unsigned n = 1 << ( d - 1 );
358  unsigned int cfgLow = 0;
359  unsigned int cfgUp = 0;
360  for ( unsigned int j = 0; j < n; ++j )
361  {
362  cfgLow += ( cfg & 1 ) << j;
363  cfg >>= 1;
364  cfgUp += ( cfg & 1 ) << j;
365  cfg >>= 1;
366  }
367  unsigned int i = openDim( z );
368  fillCfg( f, lower( z, i ), cfgLow );
369  fillCfg( f, upper( z, i ), cfgUp );
370  }
371 }
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
unsigned int dim(const Vector &z)
void fillCfg(std::map< Vector, bool > &f, const Vector &z, unsigned int cfg)
Vector upper(const Vector &z, unsigned int k)

◆ lightBetween()

template<typename Vector >
bool lightBetween ( std::map< Vector, bool > &  f,
const Vector z 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 226 of file viewDualSurface.cpp.

References DGtal::HyperRectDomain< TSpace >::begin(), dim(), domain(), DGtal::HyperRectDomain< TSpace >::end(), lower(), openDim(), and upper().

Referenced by main().

228 {
229  unsigned int d = dim( z );
230  if ( d == 0 ) return f[ z ];
231  else if ( d == 1 )
232  {
233  unsigned int i = openDim( z );
234  return f[ lower( z, i ) ] || f[ upper( z, i ) ];
235  }
236  else
237  {
238  Vector v1, v2;
239  for ( unsigned int i = 0; i < Vector::dimension; ++i )
240  {
241  v1[ i ] = ( ( z[ i ] % 2 ) == 1 ) ? z[ i ] - 1 : z[ i ];
242  v2[ i ] = ( ( z[ i ] % 2 ) == 1 ) ? z[ i ] + 1 : z[ i ];
243  }
244  Domain domain( v1, v2 );
245  for ( Domain::ConstIterator it = domain.begin(), itE = domain.end();
246  it != itE; ++it )
247  {
248  if ( *it == z ) break;
249  Point zp = z*2 - *it;
250  // std::cerr << *it << " <--> " << zp << std::endl;
251  if ( lightBetween( f, *it ) && lightBetween( f, zp ) )
252  return true;
253  }
254  return false;
255  }
256 
257 }
const ConstIterator & end() const
const Domain domain(Point(1, 2), Point(6, 5))
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
const ConstIterator & begin() const
bool lightBetween(std::map< Vector, bool > &f, const Vector &z)
MyPointD Point
Definition: testClone2.cpp:383
unsigned int dim(const Vector &z)
FreemanChain< int >::Vector Vector
Vector upper(const Vector &z, unsigned int k)

◆ lightEpsilon()

template<typename Vector >
bool lightEpsilon ( std::map< Vector, bool > &  f,
const Vector z,
unsigned int  epsilon 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 317 of file viewDualSurface.cpp.

References dim(), lower(), openDim(), and upper().

320 {
321  unsigned int d = dim( z );
322  if ( d == 0 ) return f[ z ];
323  else
324  {
325  Vector tmp( z );
326  bool eps_d = ( ( epsilon >> (d-1)) & 1 ) != 0;
327  bool val = eps_d ? true : false;
328  for ( unsigned i = 0; i < d; ++i )
329  {
330  unsigned int k = openDim( tmp );
331  tmp = lower( tmp, k );
332  if ( eps_d )
333  val = val && ( lightEpsilon( f, lower( z, k ), epsilon )
334  || lightEpsilon( f, upper( z, k ), epsilon ) );
335  else
336  val = val || ( lightEpsilon( f, lower( z, k ), epsilon )
337  && lightEpsilon( f, upper( z, k ), epsilon ) );
338  }
339  return val;
340  }
341 }
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
bool lightEpsilon(std::map< Vector, bool > &f, const Vector &z, unsigned int epsilon)
unsigned int dim(const Vector &z)
FreemanChain< int >::Vector Vector
Vector upper(const Vector &z, unsigned int k)

◆ lightMax()

template<typename Vector >
bool lightMax ( std::map< Vector, bool > &  f,
const Vector z 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 261 of file viewDualSurface.cpp.

References dim(), lower(), nbLighted(), openDim(), and upper().

263 {
264  unsigned int d = dim( z );
265  if ( d == 0 ) return f[ z ];
266  else if ( d == 1 )
267  {
268  unsigned int i = openDim( z );
269  return f[ lower( z, i ) ] || f[ upper( z, i ) ];
270  }
271  else // if ( d > 1 )
272  {
273  unsigned int n = nbLighted( f, z );
274  return n >= 2;
275  }
276 }
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
unsigned int dim(const Vector &z)
Vector upper(const Vector &z, unsigned int k)
unsigned int nbLighted(std::map< Vector, bool > &f, const Vector &z)

◆ lightMaxMin()

template<typename Vector >
bool lightMaxMin ( std::map< Vector, bool > &  f,
const Vector z 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 297 of file viewDualSurface.cpp.

References dim(), lower(), openDim(), and upper().

299 {
300  unsigned int d = dim( z );
301  if ( d == 0 ) return f[ z ];
302  else
303  {
304  Vector tmp( z );
305  bool val = false;
306  for ( unsigned i = 0; i < d; ++i )
307  {
308  unsigned int k = openDim( tmp );
309  tmp = lower( tmp, k );
310  val = val || ( lightMaxMin( f, lower( z, k ) ) && lightMaxMin( f, upper( z, k ) ) );
311  }
312  return val;
313  }
314 }
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
bool lightMaxMin(std::map< Vector, bool > &f, const Vector &z)
unsigned int dim(const Vector &z)
FreemanChain< int >::Vector Vector
Vector upper(const Vector &z, unsigned int k)

◆ lightMinMax()

template<typename Vector >
bool lightMinMax ( std::map< Vector, bool > &  f,
const Vector z 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 278 of file viewDualSurface.cpp.

References dim(), lower(), openDim(), and upper().

280 {
281  unsigned int d = dim( z );
282  if ( d == 0 ) return f[ z ];
283  else
284  {
285  Vector tmp( z );
286  bool val = true;
287  for ( unsigned i = 0; i < d; ++i )
288  {
289  unsigned int k = openDim( tmp );
290  tmp = lower( tmp, k );
291  val = val && ( lightMinMax( f, lower( z, k ) ) || lightMinMax( f, upper( z, k ) ) );
292  }
293  return val;
294  }
295 }
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
unsigned int dim(const Vector &z)
FreemanChain< int >::Vector Vector
bool lightMinMax(std::map< Vector, bool > &f, const Vector &z)
Vector upper(const Vector &z, unsigned int k)

◆ localDualVolume()

template<typename Vector >
void localDualVolume ( std::vector< Vector > &  points,
std::map< Vector, bool > &  f,
const Vector z 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 374 of file viewDualSurface.cpp.

References DGtal::HyperRectDomain< TSpace >::begin(), domain(), and DGtal::HyperRectDomain< TSpace >::end().

Referenced by main().

377 {
378  points.clear();
379  Z3i::Domain domain( z, z + Vector::diagonal(1) );
380  for ( Z3i::Domain::ConstIterator it = domain.begin(), itE = domain.end();
381  it != itE; ++it )
382  {
383  if ( f[ *it ] ) points.push_back( *it );
384  }
385 }
const ConstIterator & end() const
const Domain domain(Point(1, 2), Point(6, 5))
const ConstIterator & begin() const

◆ lower()

template<typename Vector >
Vector lower ( const Vector z,
unsigned int  k 
)

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 400 of file viewDualSurface.cpp.

References DGtal::HyperRectDomain< TSpace >::begin(), domain(), DGtal::HyperRectDomain< TSpace >::end(), fillCfg(), K, lightBetween(), localDualVolume(), naiveConvexHull(), DGtal::Viewer3D< Space, KSpace >::show(), and viewPolygons().

401 {
402  typedef KSpace::CellSet CellSet;
403  QApplication application(argc,argv);
404 
405  KSpace KS;
406 
408  viewer.show();
409  DGtal::Color fillColor( 200, 200, 220, 255 );
410  DGtal::Color surfelColor( 255, 0, 0, 150 );
411  DGtal::Color voxelColor( 150, 150, 0, 150 );
412 
413  std::vector<Vector> pts;
414 
415  unsigned int cfg = argc > 1 ? atoi( argv[1] ) : 0;
416  unsigned int cfg2 = argc > 2 ? atoi( argv[2] ) : 255;
417  std::map< Vector, bool > f;
418  for ( unsigned int y = 0; (y < 16) && (cfg <= cfg2); ++y )
419  for ( unsigned int x = 0; (x < 16) && (cfg <= cfg2); ++x, ++cfg )
420  {
421  Vector offset( x*6, y*6, 0 );
422  fillCfg( f, offset + Vector( 1, 1, 1 ), cfg );
423  Domain domain( offset + Vector( 0, 0, 0), offset + Vector( 2, 2, 2 ) );
424  KSpace K;
425  K.init( Vector( 0, 0, 0), Vector( 2, 2, 2 ), true );
426  ConfigPointPredicate<Vector> cpp( f, offset );
427  CellSet aBoundary;
428  Surfaces<KSpace>::uMakeBoundary( aBoundary, K, cpp, Vector( 0, 0, 0), Vector( 1, 1, 1 ) );
429  for ( CellSet::const_iterator it = aBoundary.begin(), itE = aBoundary.end();
430  it != itE; ++it )
431  {
432  viewer << CustomColors3D( surfelColor, surfelColor );
433  viewer << KS.uTranslation( *it, offset/2 );
434  }
435  for ( Domain::ConstIterator it = domain.begin(), itE = domain.end();
436  it != itE; ++it )
437  {
438  // lightEpsilon( f, *it, 5 ); // {1,-1,1}=5 // interesting
439  f[ *it ] = lightBetween( f, *it );
440  }
441  viewer << CustomColors3D( DGtal::Color( 255, 0, 0, 255 ), fillColor );
442  std::vector< std::vector< unsigned int > > indices;
443  Domain domain2( offset + Vector( 0, 0, 0), offset + Vector( 1, 1, 1 ) );
444 
445  for ( Domain::ConstIterator it = domain.begin(), itE = domain.end();
446  it != itE; ++it )
447  {
448  localDualVolume( pts, f, *it );
449  indices.clear();
450  naiveConvexHull( indices, pts, false ); // right_handed
451  viewPolygons( viewer, fillColor, indices, pts );
452  }
453  }
454  viewer << Viewer3D<>::updateDisplay;
455 
456  return application.exec();
457 }
const ConstIterator & end() const
const Domain domain(Point(1, 2), Point(6, 5))
Aim: A utility class for constructing surfaces (i.e. set of (n-1)-cells).
Definition: Surfaces.h:78
KhalimskySpaceND< 2, Integer > KSpace
Definition: StdDefs.h:77
void naiveConvexHull(std::vector< std::vector< unsigned int > > &indices, const std::vector< Vector > &points, bool left_handed)
void localDualVolume(std::vector< Vector > &points, std::map< Vector, bool > &f, const Vector &z)
const ConstIterator & begin() const
void viewPolygons(Viewer &viewer, const DGtal::Color &color, const std::vector< std::vector< unsigned int > > &indices, const std::vector< Vector > &points)
bool lightBetween(std::map< Vector, bool > &f, const Vector &z)
FreemanChain< int >::Vector Vector
Structure representing an RGB triple with alpha component.
Definition: Color.h:66
void fillCfg(std::map< Vector, bool > &f, const Vector &z, unsigned int cfg)
KSpace K

◆ naiveConvexHull()

template<typename Vector >
void naiveConvexHull ( std::vector< std::vector< unsigned int > > &  indices,
const std::vector< Vector > &  points,
bool  left_handed 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 81 of file viewDualSurface.cpp.

References wedge().

Referenced by main(), and wedge().

83 {
84  typedef typename Vector::Component Scalar;
85  // Checks all triplets of points.
86  std::vector< unsigned int > aFace;
87  for ( unsigned int i1 = 0; i1 < points.size(); ++i1 )
88  for ( unsigned int i2 = 0; i2 < points.size(); ++i2 )
89  if ( i1 != i2 )
90  for ( unsigned int i3 = i1 > i2 ? i1+1 : i2+1; i3 < points.size(); ++i3 )
91  {
92  Vector P12 = points[ i2 ] - points[ i1 ];
93  Vector P13 = points[ i3 ] - points[ i1 ];
94  Vector N = wedge( P12, P13 );
95  if ( N == Vector::zero ) continue;
96 
97  unsigned int nbBadPos = 0;
98  for ( unsigned int i4 = 0; i4 < points.size(); ++i4 )
99  {
100  Vector P14 = points[ i4 ] - points[ i1 ];
101  Scalar c = N.dot( P14 );
102  if ( c == 0 ) aFace.push_back( i4 );
103  else if ( ( left_handed && ( c > 0 ) )
104  || ( ! left_handed && ( c < 0 ) ) )
105  ++nbBadPos;
106  }
107  if ( nbBadPos == 0 )
108  {
109  LessThanOnFace<Vector> LTOF( N, points[ aFace[ 0 ] ], points );
110  std::sort( ++aFace.begin(), aFace.end(), LTOF );
111  indices.push_back( aFace );
112  }
113  aFace.clear();
114  }
115  // purge faces.
116  for ( unsigned int i = 0; i < indices.size(); ++i )
117  {
118  unsigned int s = indices[ i ].size();
119  for ( unsigned int j = i+1; j < indices.size(); )
120  {
121  if ( indices[ j ].size() == s )
122  {
123  bool equal = true;
124  for ( unsigned int k = 0; equal && ( k < s ); ++k )
125  if ( indices[ i ][ k ] != indices[ j ][ k ] )
126  equal = false;
127  if ( equal )
128  {
129  std::swap( indices[ j ], indices.back() );
130  indices.pop_back();
131  }
132  else
133  ++j;
134  }
135  else ++j;
136  }
137  }
138  // std::cerr << "----------- " << std::endl;
139  // for ( unsigned int i = 0; i < indices.size(); ++i )
140  // {
141  // std::cerr << "( ";
142  // for ( unsigned int j = 0; j < indices[ i ].size(); ++j )
143  // std::cerr << indices[ i ][ j ] << " ";
144  // std::cerr << ")" << std::endl;
145  // }
146 }
Vector wedge(const Vector &v1, const Vector &v2)
FreemanChain< int >::Vector Vector

◆ nbLighted()

template<typename Vector >
unsigned int nbLighted ( std::map< Vector, bool > &  f,
const Vector z 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 213 of file viewDualSurface.cpp.

References dim(), lower(), openDim(), and upper().

Referenced by lightMax().

215 { // z of dim >=2
216  unsigned int d = dim( z );
217  if ( d == 0 ) return f[ z ] ? 1 : 0;
218  unsigned int i = openDim( z );
219  return nbLighted( f, lower( z, i ) )
220  + nbLighted( f, upper( z, i ) );
221 }
Vector lower(const Vector &z, unsigned int k)
unsigned int openDim(const Vector &z)
unsigned int dim(const Vector &z)
Vector upper(const Vector &z, unsigned int k)
unsigned int nbLighted(std::map< Vector, bool > &f, const Vector &z)

◆ openDim()

template<typename Vector >
unsigned int openDim ( const Vector z)
Examples:
io/viewDualSurface.cpp.

Definition at line 191 of file viewDualSurface.cpp.

Referenced by fillCfg(), lightBetween(), lightEpsilon(), lightMax(), lightMaxMin(), lightMinMax(), and nbLighted().

192 {
193  for ( unsigned int i = 0; i < Vector::dimension; ++i )
194  if ( ( z[ i ] % 2 ) == 1 ) return i;
195  return Vector::dimension;
196 }

◆ rescale()

double rescale ( double  x)
Examples:
io/viewDualSurface.cpp.

Definition at line 148 of file viewDualSurface.cpp.

References viewPolygons().

Referenced by viewPolygons().

149 {
150  return ( x - 1.0 ) * 0.5 + 0.5;
151 }

◆ upper()

template<typename Vector >
Vector upper ( const Vector z,
unsigned int  k 
)

◆ viewPolygons()

template<typename Viewer , typename Vector >
void viewPolygons ( Viewer viewer,
const DGtal::Color color,
const std::vector< std::vector< unsigned int > > &  indices,
const std::vector< Vector > &  points 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 156 of file viewDualSurface.cpp.

References DGtal::Display3D< Space, KSpace >::addPolygon(), DGtal::Display3D< Space, KSpace >::getFillColor(), rescale(), and DGtal::Display3D< Space, KSpace >::setFillColor().

Referenced by main(), and rescale().

160 {
161  typedef typename Viewer::RealPoint RealPoint;
162  std::vector<RealPoint> pts3d;
163  DGtal::Color fillColorSave = viewer.getFillColor();
164  for ( unsigned int f = 0; f < indices.size(); ++f )
165  {
166  pts3d.clear();
167  RealPoint P;
168  for ( unsigned int v = 0; v < indices[ f ].size(); ++v )
169  {
170  unsigned int i = indices[ f ][ v ];
171  P[0] = rescale( points[ i ][ 0 ] );
172  P[1] = rescale( points[ i ][ 1 ] );
173  P[2] = rescale( points[ i ][ 2 ] );
174  pts3d.push_back( P );
175  }
176  viewer.setFillColor(color);
177  viewer.addPolygon( pts3d );
178  }
179 }
virtual void setFillColor(DGtal::Color aColor)
virtual DGtal::Color getFillColor()
Aim: Implements basic operations that will be used in Point and Vector classes.
Definition: PointVector.h:141
double rescale(double x)
void addPolygon(const std::vector< RealPoint > &vertices)
Structure representing an RGB triple with alpha component.
Definition: Color.h:66
Space::RealPoint RealPoint
Definition: StdDefs.h:97

◆ wedge()

template<typename Vector >
Vector wedge ( const Vector v1,
const Vector v2 
)
Examples:
io/viewDualSurface.cpp.

Definition at line 54 of file viewDualSurface.cpp.

References naiveConvexHull().

Referenced by naiveConvexHull().

55 {
56  return Vector( v1[ 1 ] * v2[ 2 ] - v1[ 2 ] * v2[ 1 ],
57  v1[ 2 ] * v2[ 0 ] - v1[ 0 ] * v2[ 2 ],
58  v1[ 0 ] * v2[ 1 ] - v1[ 1 ] * v2[ 0 ] );
59 }
FreemanChain< int >::Vector Vector