Integrated from CeeSol Perforce, changelist 203

AppFwk tests.
Added rotation to locator.
Caf::FrameAnimationControl : Set current frame to 0 if a framecount
change makes the current frame invalid
This commit is contained in:
sigurdp 2013-11-01 16:54:24 +01:00
parent bbebebadd5
commit df5f1f85af
61 changed files with 31246 additions and 33 deletions

16
Fwk/AppFwk/CMakeLists.txt Normal file
View File

@ -0,0 +1,16 @@
cmake_minimum_required (VERSION 2.8)
project (CeeApp)
find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED)
include (${QT_USE_FILE})
#libraries
add_subdirectory(cafProjectDataModel)
add_subdirectory(cafUserInterface)
#executables
add_subdirectory(cafTests/cafProjectDataModel_UnitTests)
add_subdirectory(cafTests/cafTestApplication)

View File

@ -0,0 +1,943 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2013 Ceetron AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This library 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 at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library 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 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfStructGrid.h"
#include "cvfStructGridCutPlane.h"
#include "cvfStructGridScalarDataAccess.h"
#include "cvfGeometryBuilderDrawableGeo.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfDebugTimer.h"
#include "cvfPlane.h"
#include "cvfScalarMapper.h"
#include "cvfEdgeKey.h"
#include "cvfMeshEdgeExtractor.h"
#include <map>
#include <cstring>
#include <math.h>
namespace cvf {
//==================================================================================================
///
/// \class cvf::StructGridCutPlane
/// \ingroup StructGrid
///
///
///
//==================================================================================================
// Based on description and implementation from Paul Bourke:
// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/
const uint StructGridCutPlane::sm_edgeTable[256] =
{
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
};
const int StructGridCutPlane::sm_triTable[256][16] =
{
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
};
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
StructGridCutPlane::StructGridCutPlane(const StructGridInterface* grid)
: m_grid(grid),
m_mapScalarSetIndex(UNDEFINED_UINT),
m_scalarMapper(NULL),
m_mapNodeAveragedScalars(false),
m_mustRecompute(true)
{
CVF_ASSERT(grid);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
StructGridCutPlane::~StructGridCutPlane()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void StructGridCutPlane::setPlane(const Plane& plane)
{
m_plane = plane;
m_mustRecompute = true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void StructGridCutPlane::setMapScalar(uint scalarSetIndex, const ScalarMapper* mapper, bool nodeAveragedScalars)
{
CVF_ASSERT(mapper);
m_mapScalarSetIndex = scalarSetIndex;
m_scalarMapper = mapper;
m_mapNodeAveragedScalars = nodeAveragedScalars;
m_mustRecompute = true;
}
//--------------------------------------------------------------------------------------------------
/// Generate cut plane geometry from current configuration
///
/// \return Reference to created DrawableGeo object. Returns NULL if no cut plane was generated
///
/// \todo Remove duplicate nodes from returned geometry
/// Current implementation is not optimized in any way
/// Should set normal from plane normal instead of relying on caller to compute them
//--------------------------------------------------------------------------------------------------
ref<DrawableGeo> StructGridCutPlane::generateSurface(const cvf::StructGridScalarDataAccess* dataAccessObject)
{
if (m_mustRecompute)
{
computeCutPlane(dataAccessObject);
m_mustRecompute = false;
}
size_t numVertices = m_vertices.size();
size_t numTriangles = m_triangleIndices.size()/3;
if (numVertices == 0 || numTriangles == 0)
{
return NULL;
}
bool doMapScalar = false;
if (m_mapScalarSetIndex != UNDEFINED_UINT && m_scalarMapper.notNull())
{
CVF_ASSERT(numVertices == m_vertexScalars.size());
doMapScalar = true;
}
ref<Vec3fArray> vertexArr = new Vec3fArray(m_vertices);
ref<UIntArray> indices = new UIntArray(m_triangleIndices);
ref<PrimitiveSetIndexedUInt> primSet = new PrimitiveSetIndexedUInt(PT_TRIANGLES);
primSet->setIndices(indices.p());
ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;;
geo->setVertexArray(vertexArr.p());
geo->addPrimitiveSet(primSet.p());
if (doMapScalar)
{
CVF_ASSERT(numVertices == m_vertexScalars.size());
ref<Color3ubArray> vertexColors = new Color3ubArray;
ref<Vec2fArray> textureCoords = new Vec2fArray;
vertexColors->reserve(numVertices);
textureCoords->reserve(numVertices);
size_t i;
for (i = 0; i < numVertices; i++)
{
Color3ub clr = m_scalarMapper->mapToColor(m_vertexScalars[i]);
vertexColors->add(clr);
Vec2f texCoord = m_scalarMapper->mapToTextureCoord(m_vertexScalars[i]);
textureCoords->add(texCoord);
}
geo->setColorArray(vertexColors.p());
geo->setTextureCoordArray(textureCoords.p());
}
//Trace::show("generateSurface(): Vertices:%d TriConns:%d Tris:%d", vertexArr->size(), indices->size(), indices->size()/3);
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<DrawableGeo> StructGridCutPlane::generateMesh(const cvf::StructGridScalarDataAccess* dataAccessObject)
{
if (m_mustRecompute)
{
computeCutPlane(dataAccessObject);
m_mustRecompute = false;
}
size_t numVertices = m_vertices.size();
size_t numLines = m_meshLineIndices.size()/2;
if (numVertices == 0 || numLines == 0)
{
return NULL;
}
MeshEdgeExtractor ee;
ee.addPrimitives(2, &m_meshLineIndices[0], m_meshLineIndices.size());
ref<UIntArray> indices = ee.lineIndices();
ref<PrimitiveSetIndexedUInt> primSet = new PrimitiveSetIndexedUInt(PT_LINES);
primSet->setIndices(indices.p());
ref<Vec3fArray> vertexArr = new Vec3fArray(m_vertices);
ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;;
geo->setVertexArray(vertexArr.p());
geo->addPrimitiveSet(primSet.p());
//Trace::show("generateMesh(): Vertices:%d LineConns:%d Lines:%d", vertexArr->size(), indices->size(), indices->size()/2);
return geo;
}
//--------------------------------------------------------------------------------------------------
/// Generate surface representation of the specified cut plane
///
/// \note Will compute normals before returning geometry
//--------------------------------------------------------------------------------------------------
void StructGridCutPlane::computeCutPlane(const cvf::StructGridScalarDataAccess* dataAccessObject)
{
if (!dataAccessObject) return;
DebugTimer tim("");
bool doMapScalar = false;
if (m_mapScalarSetIndex != UNDEFINED_UINT && m_scalarMapper.notNull())
{
doMapScalar = true;
}
size_t cellCountI = m_grid->cellCountI();
size_t cellCountJ = m_grid->cellCountJ();
size_t cellCountK = m_grid->cellCountK();
// Clear any current data
m_vertices.clear();
m_vertexScalars.clear();
m_triangleIndices.clear();
m_meshLineIndices.clear();
// The indexing conventions for vertices and
// edges used in the algorithm:
// edg verts
// 4-------------5 *------4------* 0 0 - 1
// /| /| /| /| 1 1 - 2
// / | / | 7/ | 5/ | 2 2 - 3
// / | / | |z / 8 / 9 3 3 - 0
// 7-------------6 | | /y *------6------* | 4 4 - 5
// | | | | |/ | | | | 5 5 - 6
// | 0---------|---1 *---x | *------0--|---* 6 6 - 7
// | / | / 11 / 10 / 7 7 - 4
// | / | / | /3 | /1 8 0 - 4
// |/ |/ |/ |/ 9 1 - 5
// 3-------------2 *------2------* 10 2 - 6
// vertex indices edge indices 11 3 - 7
//
size_t k;
for (k = 0; k < cellCountK; k++)
{
size_t j;
for (j = 0; j < cellCountJ; j++)
{
size_t i;
for (i = 0; i < cellCountI; i++)
{
size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k);
Vec3d minCoord;
Vec3d maxCoord;
m_grid->cellMinMaxCordinates(cellIndex, &minCoord, &maxCoord);
// Early reject for cells outside clipping box
if (m_clippingBoundingBox.isValid())
{
BoundingBox cellBB(minCoord, maxCoord);
if (!m_clippingBoundingBox.intersects(cellBB))
{
continue;
}
}
// Check if plane intersects this cell and skip if it doesn't
if (!isCellIntersectedByPlane(m_plane, minCoord, maxCoord))
{
continue;
}
GridCell cell;
bool isClipped = false;
if (m_clippingBoundingBox.isValid())
{
if (!m_clippingBoundingBox.contains(minCoord) || !m_clippingBoundingBox.contains(maxCoord))
{
isClipped = true;
minCoord.x() = CVF_MAX(minCoord.x(), m_clippingBoundingBox.min().x());
minCoord.y() = CVF_MAX(minCoord.y(), m_clippingBoundingBox.min().y());
minCoord.z() = CVF_MAX(minCoord.z(), m_clippingBoundingBox.min().z());
maxCoord.x() = CVF_MIN(maxCoord.x(), m_clippingBoundingBox.max().x());
maxCoord.y() = CVF_MIN(maxCoord.y(), m_clippingBoundingBox.max().y());
maxCoord.z() = CVF_MIN(maxCoord.z(), m_clippingBoundingBox.max().z());
}
}
cell.p[0].set(minCoord.x(), maxCoord.y(), minCoord.z());
cell.p[1].set(maxCoord.x(), maxCoord.y(), minCoord.z());
cell.p[2].set(maxCoord.x(), minCoord.y(), minCoord.z());
cell.p[3].set(minCoord.x(), minCoord.y(), minCoord.z());
cell.p[4].set(minCoord.x(), maxCoord.y(), maxCoord.z());
cell.p[5].set(maxCoord.x(), maxCoord.y(), maxCoord.z());
cell.p[6].set(maxCoord.x(), minCoord.y(), maxCoord.z());
cell.p[7].set(minCoord.x(), minCoord.y(), maxCoord.z());
// Fetch scalar values
double cellScalarValue = 0;
if (doMapScalar)
{
cellScalarValue = dataAccessObject->cellScalar(cellIndex);
// If we're doing node averaging we must populate grid cell with scalar values interpolated to the grid points
if (m_mapNodeAveragedScalars)
{
CVF_ASSERT(false); // This is not supported in this code.
#if 0
// This is not supported now. This is possibly valid code for "neighbour regular grids" (Eg. Rectilinear or regular grids)
// but is not general for general struct grids. So the interpolation stuff must be handled specially for each "real" grid type
if (isClipped)
{
double scalarVal;
if (dataAccessObject->pointScalar(cell.p[0], &scalarVal)) cell.s[0] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[1], &scalarVal)) cell.s[1] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[2], &scalarVal)) cell.s[2] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[3], &scalarVal)) cell.s[3] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[4], &scalarVal)) cell.s[4] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[5], &scalarVal)) cell.s[5] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[6], &scalarVal)) cell.s[6] = scalarVal;
if (dataAccessObject->pointScalar(cell.p[7], &scalarVal)) cell.s[7] = scalarVal;
}
else
{
cell.s[0] = dataAccessObject->gridPointScalar(i, j + 1, k);
cell.s[1] = dataAccessObject->gridPointScalar(i + 1, j + 1, k);
cell.s[2] = dataAccessObject->gridPointScalar(i + 1, j, k);
cell.s[3] = dataAccessObject->gridPointScalar(i, j, k);
cell.s[4] = dataAccessObject->gridPointScalar(i, j + 1, k + 1);
cell.s[5] = dataAccessObject->gridPointScalar(i + 1, j + 1, k + 1);
cell.s[6] = dataAccessObject->gridPointScalar(i + 1, j, k + 1);
cell.s[7] = dataAccessObject->gridPointScalar(i, j, k + 1);
}
#else
cell.s[0] = HUGE_VAL;
cell.s[1] = HUGE_VAL;
cell.s[2] = HUGE_VAL;
cell.s[3] = HUGE_VAL;
cell.s[4] = HUGE_VAL;
cell.s[5] = HUGE_VAL;
cell.s[6] = HUGE_VAL;
cell.s[7] = HUGE_VAL;
#endif
}
}
Triangles triangles;
uint numTriangles = polygonise(m_plane, cell, &triangles);
if (numTriangles > 0)
{
// Add all the referenced vertices
// At the same time registering their index in the 'global' vertex list
uint globalVertexIndices[12];
int iv;
for (iv = 0; iv < 12; iv++)
{
if (triangles.usedVertices[iv])
{
globalVertexIndices[iv] = static_cast<uint>(m_vertices.size());
m_vertices.push_back(Vec3f(triangles.vertices[iv]));
if (doMapScalar)
{
if (m_mapNodeAveragedScalars)
{
m_vertexScalars.push_back(triangles.scalars[iv]);
}
else
{
m_vertexScalars.push_back(cellScalarValue);
}
}
}
else
{
globalVertexIndices[iv] = UNDEFINED_UINT;
}
}
// Build triangles from the cell
const size_t prevNumTriangleIndices = m_triangleIndices.size();
uint t;
for (t = 0; t < numTriangles; t++)
{
m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t]]);
m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t + 1]]);
m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t + 2]]);
}
// Add mesh line indices
addMeshLineIndices(&m_triangleIndices[prevNumTriangleIndices], numTriangles);
}
}
}
}
// Trace::show("Vertices:%d TriConns:%d Tris:%d", m_vertices.size(), m_triangleIndices.size(), m_triangleIndices.size()/3);
// tim.reportTimeMS("computeCutPlane()");
}
//--------------------------------------------------------------------------------------------------
/// Add mesh line indices by analyzing the triangle indices and only adding 'unique' edges
//--------------------------------------------------------------------------------------------------
void StructGridCutPlane::addMeshLineIndices(const uint* triangleIndices, uint triangleCount)
{
std::vector<int64> edges;
edges.reserve(3*triangleCount);
std::vector<int64>::iterator it;
uint t;
for (t = 0; t < triangleCount; t++)
{
uint i;
for (i = 0; i < 3; i++)
{
const uint vertexIdx1 = triangleIndices[3*t + i];
const uint vertexIdx2 = (i < 2) ? triangleIndices[3*t + i + 1] : triangleIndices[3*t];
int64 edgeKeyVal = EdgeKey(vertexIdx1, vertexIdx2).toKeyVal();
it = find(edges.begin(), edges.end(), edgeKeyVal);
if (it == edges.end())
{
edges.push_back(edgeKeyVal);
}
else
{
edges.erase(it);
}
}
}
for (it = edges.begin(); it != edges.end(); ++it)
{
EdgeKey ek = EdgeKey::fromkeyVal(*it);
m_meshLineIndices.push_back(ek.index1());
m_meshLineIndices.push_back(ek.index2());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint StructGridCutPlane::polygonise(const Plane& plane, const GridCell& cell, Triangles* triangles)
{
int cubeindex = 0;
if (plane.distanceSquared(cell.p[0]) < 0) cubeindex |= 1;
if (plane.distanceSquared(cell.p[1]) < 0) cubeindex |= 2;
if (plane.distanceSquared(cell.p[2]) < 0) cubeindex |= 4;
if (plane.distanceSquared(cell.p[3]) < 0) cubeindex |= 8;
if (plane.distanceSquared(cell.p[4]) < 0) cubeindex |= 16;
if (plane.distanceSquared(cell.p[5]) < 0) cubeindex |= 32;
if (plane.distanceSquared(cell.p[6]) < 0) cubeindex |= 64;
if (plane.distanceSquared(cell.p[7]) < 0) cubeindex |= 128;
if (sm_edgeTable[cubeindex] == 0)
{
return 0;
}
// Compute vertex coordinates on the edges where we have intersections
if (sm_edgeTable[cubeindex] & 1) triangles->vertices[0] = planeLineIntersection(plane, cell.p[0], cell.p[1], cell.s[0], cell.s[1], &triangles->scalars[0] );
if (sm_edgeTable[cubeindex] & 2) triangles->vertices[1] = planeLineIntersection(plane, cell.p[1], cell.p[2], cell.s[1], cell.s[2], &triangles->scalars[1] );
if (sm_edgeTable[cubeindex] & 4) triangles->vertices[2] = planeLineIntersection(plane, cell.p[2], cell.p[3], cell.s[2], cell.s[3], &triangles->scalars[2] );
if (sm_edgeTable[cubeindex] & 8) triangles->vertices[3] = planeLineIntersection(plane, cell.p[3], cell.p[0], cell.s[3], cell.s[0], &triangles->scalars[3] );
if (sm_edgeTable[cubeindex] & 16) triangles->vertices[4] = planeLineIntersection(plane, cell.p[4], cell.p[5], cell.s[4], cell.s[5], &triangles->scalars[4] );
if (sm_edgeTable[cubeindex] & 32) triangles->vertices[5] = planeLineIntersection(plane, cell.p[5], cell.p[6], cell.s[5], cell.s[6], &triangles->scalars[5] );
if (sm_edgeTable[cubeindex] & 64) triangles->vertices[6] = planeLineIntersection(plane, cell.p[6], cell.p[7], cell.s[6], cell.s[7], &triangles->scalars[6] );
if (sm_edgeTable[cubeindex] & 128) triangles->vertices[7] = planeLineIntersection(plane, cell.p[7], cell.p[4], cell.s[7], cell.s[4], &triangles->scalars[7] );
if (sm_edgeTable[cubeindex] & 256) triangles->vertices[8] = planeLineIntersection(plane, cell.p[0], cell.p[4], cell.s[0], cell.s[4], &triangles->scalars[8] );
if (sm_edgeTable[cubeindex] & 512) triangles->vertices[9] = planeLineIntersection(plane, cell.p[1], cell.p[5], cell.s[1], cell.s[5], &triangles->scalars[9] );
if (sm_edgeTable[cubeindex] & 1024) triangles->vertices[10] = planeLineIntersection(plane, cell.p[2], cell.p[6], cell.s[2], cell.s[6], &triangles->scalars[10]);
if (sm_edgeTable[cubeindex] & 2048) triangles->vertices[11] = planeLineIntersection(plane, cell.p[3], cell.p[7], cell.s[3], cell.s[7], &triangles->scalars[11]);
// Create the triangles
memset(triangles->usedVertices, 0, sizeof(triangles->usedVertices));
const int* triConnects = sm_triTable[cubeindex];
uint n = 0;
while (triConnects[n] != -1)
{
triangles->triangleIndices[n] = triConnects[n];
triangles->usedVertices[triConnects[n]] = true;
n++;
}
uint numTriangles = n/3;
return numTriangles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Vec3d StructGridCutPlane::planeLineIntersection(const Plane& plane, const Vec3d& p1, const Vec3d& p2, const double s1, const double s2, double* s)
{
// From http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/
//
// P1 (x1,y1,z1) and P2 (x2,y2,z2)
//
// P = P1 + u (P2 - P1)
//
// A*x1 + B*y1 + C*z1 + D
// u = ---------------------------------
// A*(x1-x2) + B*(y1-y2) + C*(z1-z2)
CVF_ASSERT(s);
const Vec3d v = p2 - p1;
double denominator = -(plane.A()*v.x() + plane.B()*v.y() + plane.C()*v.z());
if (denominator != 0)
{
double u = (plane.A()*p1.x() + plane.B()*p1.y() + plane.C()*p1.z() + plane.D())/denominator;
if (u > 0.0 && u < 1.0)
{
*s = s1 + u*(s2 - s1);
return (p1 + u*v);
}
else
{
if (u >= 1.0)
{
*s = s2;
return p2;
}
else
{
*s = s1;
return p1;
}
}
}
else
{
*s = s1;
return p1;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool StructGridCutPlane::isCellIntersectedByPlane(const Plane& plane, const Vec3d& cellMinCoord, const Vec3d& cellMaxCoord)
{
// See http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html
// Start by finding the "positive vertex" and the "negative vertex" relative to plane normal
Vec3d pVertex(cellMinCoord);
Vec3d nVertex(cellMaxCoord);
if (plane.A() >= 0)
{
pVertex.x() = cellMaxCoord.x();
nVertex.x() = cellMinCoord.x();
}
if (plane.B() >= 0)
{
pVertex.y() = cellMaxCoord.y();
nVertex.y() = cellMinCoord.y();
}
if (plane.C() >= 0)
{
pVertex.z() = cellMaxCoord.z();
nVertex.z() = cellMinCoord.z();
}
// Chek if both positive and negative vertex are on same side of plane
if (plane.distanceSquared(pVertex) < 0)
{
if (plane.distanceSquared(nVertex) < 0)
{
return false;
}
else
{
return true;
}
}
else
{
if (plane.distanceSquared(nVertex) >= 0)
{
return false;
}
else
{
return true;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void StructGridCutPlane::setClippingBoundingBox(const BoundingBox& boundingBox)
{
m_clippingBoundingBox = boundingBox;
}
} // namespace cvf

View File

@ -0,0 +1,113 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2013 Ceetron AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This library 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 at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library 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 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#pragma once
#include "cvfPlane.h"
#include "cvfBoundingBox.h"
#include <vector>
namespace cvf {
class DrawableGeo;
class StructGridInterface;
class ScalarMapper;
class StructGridScalarDataAccess;
//==================================================================================================
//
//
//
//==================================================================================================
class StructGridCutPlane : public Object
{
public:
StructGridCutPlane(const StructGridInterface* grid);
~StructGridCutPlane();
void setPlane(const Plane& plane);
void setClippingBoundingBox(const BoundingBox& boundingBox);
void setMapScalar(uint scalarSetIndex, const ScalarMapper* mapper, bool nodeAveragedScalars);
ref<DrawableGeo> generateSurface(const cvf::StructGridScalarDataAccess* dataAccessObject);
ref<DrawableGeo> generateMesh(const cvf::StructGridScalarDataAccess* dataAccessObject);
private:
struct GridCell
{
Vec3d p[8]; // Cell's corner coordinates
double s[8]; // Scalar values in cell corners
};
struct Triangles
{
Vec3d vertices[12]; // The vertices, one on each edge in the cell
double scalars[12]; // Interpolated scalar values for the vertices
bool usedVertices[12]; // Flag to indicate which of the vertices (and scalars) are being referenced by the triangle indices
int triangleIndices[15];// Triangle indices (into vertices), max 5 triangles.
};
private:
void computeCutPlane(const cvf::StructGridScalarDataAccess* dataAccessObject);
void addMeshLineIndices(const uint* triangleIndices, uint triangleCount);
static uint polygonise(const Plane& plane, const GridCell& cell, Triangles* triangles);
static Vec3d planeLineIntersection(const Plane& plane, const Vec3d& p1, const Vec3d& p2, const double s1, const double s2, double* s);
static bool isCellIntersectedByPlane(const Plane& plane, const Vec3d& cellMinCoord, const Vec3d& cellMaxCoord);
private:
cref<StructGridInterface> m_grid;
Plane m_plane;
BoundingBox m_clippingBoundingBox;
uint m_mapScalarSetIndex; // Index of scalar set that should be mapped onto the cut plane. -1 for no mapping
cref<ScalarMapper> m_scalarMapper; // Scalar mapper to use when mapping. Both scalar set index and mapper must be set in order to get scalar mapping
bool m_mapNodeAveragedScalars; // If true we'll compute node averaged scalars before mapping them on the cut plane. If false per cell scalars will be mapped.
bool m_mustRecompute; // Flag to indicate that cut plane must be recomputed
std::vector<Vec3f> m_vertices; // Vertices of computed surface
std::vector<double> m_vertexScalars; // Scalar values for vertices
std::vector<uint> m_triangleIndices; // Triangle connectivities
std::vector<uint> m_meshLineIndices; // Mesh line connectivities
static const uint sm_edgeTable[256];
static const int sm_triTable[256][16];
};
}

1817
Fwk/AppFwk/Doxygen/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -163,7 +163,11 @@ int FrameAnimationControl::currentFrame() const
void FrameAnimationControl::setNumFrames(int numFrames)
{
m_numFrames = numFrames < 0 ? 0 : numFrames;
emit frameCountChanged(m_numFrames);
if (m_currentFrame >= numFrames ) m_currentFrame = 0; // Should we emit frameChanged ?
}
//--------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,37 @@
cmake_minimum_required (VERSION 2.8)
project ( cafProjectDataModel_UnitTests )
include_directories (
${CMAKE_SOURCE_DIR}/cafProjectDataModel
${CMAKE_SOURCE_DIR}/cafTests
#Remove when RigStatistics is out
${ResInsight_SOURCE_DIR}/ApplicationCode/ModelVisualization
)
# add the executable
add_executable (${PROJECT_NAME}
cafPdmBasicTest.cpp
cafProjectDataModel_UnitTests.cpp
${CMAKE_SOURCE_DIR}/cafTests/gtest/gtest-all.cpp
)
target_link_libraries ( ${PROJECT_NAME}
cafProjectDataModel
${QT_LIBRARIES}
)
# Copy Qt Dlls
if (MSVC)
set (QTLIBLIST QtCore QtGui )
foreach (qtlib ${QTLIBLIST})
# Debug
execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll)
# Release
execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll)
endforeach( qtlib )
endif(MSVC)

View File

@ -0,0 +1,744 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2013 Ceetron AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This library 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 at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library 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 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include <iostream>
#include "gtest/gtest.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
#include "cafPdmDocument.h"
#include "cafAppEnum.h"
#include <memory>
#include <QFile>
/// Demo objects to show the usage of the Pdm system
class SimpleObj: public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
SimpleObj()
{
CAF_PDM_InitObject("Simple Object", "", "", "");
CAF_PDM_InitField(&m_position, "Position", 8765.2, "Position", "", "", "");
CAF_PDM_InitField(&m_dir, "Dir", 123.56, "Direction", "", "", "");
CAF_PDM_InitField(&m_up, "Up", 0.0, "Up value", "", "", "" );
CAF_PDM_InitFieldNoDefault(&m_numbers, "Numbers", "Important Numbers", "", "", "");
}
/// Assignment and copying of PDM objects is not focus for the features. This is only a
/// "would it work" test
SimpleObj(const SimpleObj& other)
: PdmObject()
{
CAF_PDM_InitField(&m_position, "Position", 8765.2, "Position", "", "", "");
CAF_PDM_InitField(&m_dir, "Dir", 123.56, "Direction", "", "", "");
CAF_PDM_InitField(&m_up, "Up", 0.0, "Up value", "", "", "" );
CAF_PDM_InitFieldNoDefault(&m_numbers, "Numbers", "Important Numbers", "", "", "");
m_position = other.m_position;
m_dir = other.m_dir;
m_up = other.m_up;
m_numbers = other.m_numbers;
}
~SimpleObj() {}
caf::PdmField<double> m_position;
caf::PdmField<double> m_dir;
caf::PdmField<double> m_up;
caf::PdmField<std::vector<double> > m_numbers;
};
CAF_PDM_SOURCE_INIT(SimpleObj, "SimpleObj");
class DemoPdmObject: public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
DemoPdmObject()
{
CAF_PDM_InitObject("Demo Object", "", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework");
CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "",
"Enter a big number here",
"This is a place you can enter a big real value if you want" );
CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number","",
"Enter some small number here",
"This is a place you can enter a small integer value if you want");
CAF_PDM_InitField(&m_textField, "TextField", QString("ÆØÅ Test text end"), "", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_simpleObjPtrField, "SimpleObjPtrField", "", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_simpleObjPtrField2, "SimpleObjPtrField2", "", "", "", "");
m_simpleObjPtrField2 = new SimpleObj;
}
~DemoPdmObject()
{
delete m_simpleObjPtrField2();
}
// Fields
caf::PdmField<double> m_doubleField;
caf::PdmField<int> m_intField;
caf::PdmField<QString> m_textField;
caf::PdmField<SimpleObj*> m_simpleObjPtrField;
caf::PdmField<SimpleObj*> m_simpleObjPtrField2;
};
CAF_PDM_SOURCE_INIT(DemoPdmObject, "DemoPdmObject");
class InheritedDemoObj : public DemoPdmObject
{
CAF_PDM_HEADER_INIT;
public:
enum TestEnumType
{
T1, T2, T3
};
InheritedDemoObj()
{
CAF_PDM_InitFieldNoDefault(&m_texts, "Texts", "Some words", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_testEnumField, "TestEnumValue", "An Enum", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_simpleObjectsField, "SimpleObjects", "A child object", "", "", "");
}
caf::PdmField<std::vector<QString> > m_texts;
caf::PdmField< caf::AppEnum<TestEnumType> > m_testEnumField;
caf::PdmPointersField<SimpleObj*> m_simpleObjectsField;
};
CAF_PDM_SOURCE_INIT(InheritedDemoObj, "InheritedDemoObj");
namespace caf
{
template<>
void AppEnum<InheritedDemoObj::TestEnumType>::setUp()
{
addItem(InheritedDemoObj::T1, "T1", "An A letter");
addItem(InheritedDemoObj::T2, "T2", "A B letter");
addItem(InheritedDemoObj::T3, "T3", "A B letter");
setDefault(InheritedDemoObj::T1);
}
}
//--------------------------------------------------------------------------------------------------
/// This is a testbed to try out different aspects, instead of having a main in a prototype program
/// To be disabled when everything gets more mature.
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, Start)
{
DemoPdmObject* a = new DemoPdmObject;
caf::PdmObject* demo = caf::PdmObjectFactory::instance()->create("DemoPdmObject");
EXPECT_TRUE(demo != NULL);
QString xml;
QXmlStreamWriter xmlStream(&xml);
xmlStream.setAutoFormatting(true);
SimpleObj* s2 = new SimpleObj;
caf::PdmPointer<SimpleObj> sp;
sp = s2;
std::cout << sp.p() << std::endl;
{
SimpleObj s;
s.m_dir = 10000;
sp = &s;
a->m_textField = "Hei og hå";
*s2 = s;
a->m_simpleObjPtrField = s2;
s.writeFields(xmlStream);
}
a->writeFields(xmlStream);
caf::PdmObjectGroup og;
og.objects.push_back(a);
og.objects.push_back(s2);
og.writeFields(xmlStream);
std::cout << sp.p() << std::endl,
std::cout << xml.toStdString() << std::endl;
}
//--------------------------------------------------------------------------------------------------
/// Test of PdmField operations
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, NormalPdmField)
{
std::vector<double> testValue;
testValue.push_back(1.1);
testValue.push_back(1.2);
testValue.push_back(1.3);
std::vector<double> testValue2;
testValue2.push_back(2.1);
testValue2.push_back(2.2);
testValue2.push_back(2.3);
// Constructors
caf::PdmField<std::vector<double> > field2(testValue);
EXPECT_EQ(1.3, field2.v()[2]);
caf::PdmField<std::vector<double> > field3(field2);
EXPECT_EQ(1.3, field3.v()[2]);
caf::PdmField<std::vector<double> > field1;
EXPECT_EQ(size_t(0), field1().size());
// Operators
EXPECT_FALSE(field1 == field3);
field1 = field2;
EXPECT_EQ(1.3, field1()[2]);
field1 = testValue2;
EXPECT_EQ(2.3, field1()[2]);
field3 = field1;
EXPECT_TRUE(field1 == field3);
}
//--------------------------------------------------------------------------------------------------
/// Test of PdmField of pointer operations
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, PointerPdmField)
{
SimpleObj* testValue = new SimpleObj;
testValue->m_numbers.v().push_back(1.1);
testValue->m_numbers.v().push_back(1.2);
testValue->m_numbers.v().push_back(1.3);
SimpleObj* testValue2 = new SimpleObj;
testValue->m_numbers.v().push_back(2.1);
testValue->m_numbers.v().push_back(2.2);
testValue->m_numbers.v().push_back(2.3);
// Constructors
caf::PdmField<SimpleObj*> field2(testValue);
EXPECT_EQ(testValue, field2.v());
caf::PdmField<SimpleObj*> field3(field2);
EXPECT_EQ(testValue, field3.v());
caf::PdmField<SimpleObj*> field1;
EXPECT_EQ((SimpleObj*)0, field1.v());
// Operators
EXPECT_FALSE(field1 == field3);
field1 = field2;
EXPECT_EQ(testValue, field1);
field1 = testValue2;
field3 = testValue2;
EXPECT_EQ(testValue2, field1);
EXPECT_TRUE(field1 == field3);
delete testValue;
delete testValue2;
EXPECT_EQ((SimpleObj*)0, field1);
EXPECT_EQ((SimpleObj*)0, field2);
EXPECT_EQ((SimpleObj*)0, field3);
}
//--------------------------------------------------------------------------------------------------
/// Test of PdmPointersField operations
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, PdmPointersField)
{
std::vector<caf::PdmFieldHandle*> parentFields;
InheritedDemoObj* ihd1 = new InheritedDemoObj;
SimpleObj* s1 = new SimpleObj;
SimpleObj* s2 = new SimpleObj;
SimpleObj* s3 = new SimpleObj;
// empty() number 1
EXPECT_TRUE(ihd1->m_simpleObjectsField.empty());
EXPECT_EQ(size_t(0), ihd1->m_simpleObjectsField.size());
// push_back()
ihd1->m_simpleObjectsField.push_back(s1);
ihd1->m_simpleObjectsField.push_back(s2);
ihd1->m_simpleObjectsField.push_back(s3);
s1->parentFields(parentFields);
EXPECT_EQ(size_t(1), parentFields.size());
parentFields.clear();
// size()
EXPECT_EQ(size_t(3), ihd1->m_simpleObjectsField.size());
EXPECT_EQ(size_t(3), ihd1->m_simpleObjectsField.size());
// operator[]
EXPECT_EQ(s2, ihd1->m_simpleObjectsField[1]);
EXPECT_EQ(s3, ihd1->m_simpleObjectsField[2]);
// childObjects
std::vector<caf::PdmObject*> objects;
ihd1->m_simpleObjectsField.childObjects(&objects);
EXPECT_EQ(size_t(3), objects.size());
// Operator ==, Operator =
InheritedDemoObj* ihd2 = new InheritedDemoObj;
EXPECT_FALSE(ihd2->m_simpleObjectsField == ihd1->m_simpleObjectsField);
ihd2->m_simpleObjectsField = ihd1->m_simpleObjectsField;
EXPECT_TRUE(ihd2->m_simpleObjectsField == ihd1->m_simpleObjectsField);
s1->parentFields(parentFields);
EXPECT_EQ(size_t(2), parentFields.size());
parentFields.clear();
// set(), Operator=
ihd2->m_simpleObjectsField.set(1, NULL);
EXPECT_FALSE(ihd2->m_simpleObjectsField == ihd1->m_simpleObjectsField);
EXPECT_TRUE(NULL == ihd2->m_simpleObjectsField[1]);
s2->parentFields(parentFields);
EXPECT_EQ(size_t(1), parentFields.size());
parentFields.clear();
// removeAll(pointer)
ihd2->m_simpleObjectsField.removeChildObject(NULL);
EXPECT_EQ(size_t(2), ihd2->m_simpleObjectsField.size());
EXPECT_EQ(s3, ihd2->m_simpleObjectsField[1]);
EXPECT_EQ(s1, ihd2->m_simpleObjectsField[0]);
// insert()
ihd2->m_simpleObjectsField.insert(1, s2);
EXPECT_TRUE(ihd2->m_simpleObjectsField == ihd1->m_simpleObjectsField);
s2->parentFields(parentFields);
EXPECT_EQ(size_t(2), parentFields.size());
parentFields.clear();
// erase (index)
ihd2->m_simpleObjectsField.erase(1);
EXPECT_EQ(size_t(2), ihd2->m_simpleObjectsField.size());
EXPECT_EQ(s3, ihd2->m_simpleObjectsField[1]);
EXPECT_EQ(s1, ihd2->m_simpleObjectsField[0]);
s2->parentFields(parentFields);
EXPECT_EQ(size_t(1), parentFields.size());
parentFields.clear();
// clear()
ihd2->m_simpleObjectsField.clear();
EXPECT_EQ(size_t(0), ihd2->m_simpleObjectsField.size());
s1->parentFields(parentFields);
EXPECT_EQ(size_t(1), parentFields.size());
parentFields.clear();
}
template <>
inline void GTestStreamToHelper<QString>(std::ostream* os, const QString& val) {
*os << val.toLatin1().data();
}
//--------------------------------------------------------------------------------------------------
/// Tests the roundtrip: Create, write, read, write and checks that the first and second file are identical
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, ReadWrite)
{
QString xmlDocumentContentWithErrors;
{
caf::PdmDocument xmlDoc;
// Create objects
DemoPdmObject* d1 = new DemoPdmObject;
DemoPdmObject* d2 = new DemoPdmObject;
InheritedDemoObj* id1 = new InheritedDemoObj;
InheritedDemoObj* id2 = new InheritedDemoObj;
SimpleObj* s1 = new SimpleObj;
SimpleObj s2;
s1->m_numbers.v().push_back(1.7);
// set some values
s2.m_numbers.v().push_back(2.4);
s2.m_numbers.v().push_back(2.5);
s2.m_numbers.v().push_back(2.6);
s2.m_numbers.v().push_back(2.7);
id1->m_texts.v().push_back("Hei");
id1->m_texts.v().push_back("og");
id1->m_texts.v().push_back("Hå test with whitespace");
d2->m_simpleObjPtrField = &s2;
d2->m_simpleObjPtrField2 = s1;
id1->m_simpleObjectsField.push_back(s1);
id1->m_simpleObjectsField.push_back(&s2);
id1->m_simpleObjectsField.push_back(&s2);
id1->m_simpleObjectsField.push_back(&s2);
// Add to document
xmlDoc.addObject(d1);
xmlDoc.addObject(d2);
xmlDoc.addObject(s1);
xmlDoc.addObject(id1);
xmlDoc.addObject(id2);
// Write file
xmlDoc.fileName = "PdmTestFil.xml";
xmlDoc.writeFile();
{
std::vector<caf::PdmPointer<DemoPdmObject> > demoObjs;
xmlDoc.objectsByType(&demoObjs);
EXPECT_EQ(size_t(4), demoObjs.size());
}
{
std::vector<caf::PdmPointer<InheritedDemoObj> > demoObjs;
xmlDoc.objectsByType(&demoObjs);
EXPECT_EQ(size_t(2), demoObjs.size());
}
{
std::vector<caf::PdmPointer<SimpleObj> > demoObjs;
xmlDoc.objectsByType(&demoObjs);
EXPECT_EQ(size_t(1), demoObjs.size());
}
xmlDoc.deleteObjects();
EXPECT_EQ(size_t(0), xmlDoc.objects().size());
}
{
caf::PdmDocument xmlDoc;
// Read file
xmlDoc.fileName = "PdmTestFil.xml";
xmlDoc.readFile();
// Test sample of that writing actually took place
std::vector<caf::PdmPointer<InheritedDemoObj> > ihDObjs;
xmlDoc.objectsByType(&ihDObjs);
EXPECT_EQ(size_t(2),ihDObjs.size() );
ASSERT_EQ(size_t(4), ihDObjs[0]->m_simpleObjectsField.size());
ASSERT_EQ(size_t(4), ihDObjs[0]->m_simpleObjectsField[1]->m_numbers().size());
EXPECT_EQ(2.7, ihDObjs[0]->m_simpleObjectsField[1]->m_numbers()[3]);
EXPECT_EQ(QString("ÆØÅ Test text end"), ihDObjs[0]->m_textField());
// Write file
QFile xmlFile("PdmTestFil2.xml");
xmlFile.open(QIODevice::WriteOnly);
xmlDoc.writeFile(&xmlFile);
xmlFile.close();
}
// Check that the files are identical
{
QFile f1("PdmTestFil.xml");
QFile f2("PdmTestFil2.xml");
f1.open(QIODevice::ReadOnly);
f2.open(QIODevice::ReadOnly);
QByteArray ba1 = f1.readAll();
QByteArray ba2 = f2.readAll();
bool equal = ba1 == ba2;
EXPECT_TRUE(equal);
// Then test how errors are handled
{
int pos = 0;
int occurenceCount = 0;
while (occurenceCount < 1)
{
pos = ba1.indexOf("<SimpleObj>", pos+1);
occurenceCount++;
}
ba1.insert(pos+1, "Error");
}
{
int pos = 0;
int occurenceCount = 0;
while (occurenceCount < 1)
{
pos = ba1.indexOf("</SimpleObj>", pos +1);
occurenceCount++;
}
ba1.insert(pos+2, "Error");
}
{
int pos = 0;
int occurenceCount = 0;
while (occurenceCount < 6) // Second position in a pointersfield
{
pos = ba1.indexOf("<SimpleObj>", pos +1);
occurenceCount++;
}
ba1.insert(pos+1, "Error");
}
{
int pos = 0;
int occurenceCount = 0;
while (occurenceCount < 6) // Second position in a pointersfield
{
pos = ba1.indexOf("</SimpleObj>", pos +1);
occurenceCount++;
}
ba1.insert(pos+2, "Error");
}
{
int pos = ba1.indexOf("<BigNumber>");
ba1.insert(pos+1, "Error");
pos = ba1.indexOf("</BigNumber>");
ba1.insert(pos+2, "Error");
}
{
int pos = 0;
int occurenceCount = 0;
while (occurenceCount < 4)
{
pos = ba1.indexOf("<Numbers>", pos +1);
occurenceCount++;
}
ba1.insert(pos+1, "Error");
}
{
int pos = 0;
int occurenceCount = 0;
while (occurenceCount < 4)
{
pos = ba1.indexOf("</Numbers>", pos +1);
occurenceCount++;
}
ba1.insert(pos+2, "Error");
}
// Write the edited document
QFile f3("PdmTestFilWithError.xml");
f3.open(QIODevice::WriteOnly);
f3.write(ba1);
f3.close();
// Read the document containing errors
caf::PdmDocument xmlErrorDoc;
xmlErrorDoc.fileName = "PdmTestFilWithError.xml";
xmlErrorDoc.readFile();
// Check the pointersfield
std::vector<caf::PdmPointer<InheritedDemoObj> > ihDObjs;
xmlErrorDoc.objectsByType(&ihDObjs);
EXPECT_EQ(size_t(2), ihDObjs.size() );
ASSERT_EQ(size_t(3), ihDObjs[0]->m_simpleObjectsField.size());
// check single pointer field
std::vector<caf::PdmPointer<DemoPdmObject> > demoObjs;
xmlErrorDoc.objectsByType(&demoObjs);
EXPECT_EQ(size_t(4), demoObjs.size() );
EXPECT_TRUE(demoObjs[0]->m_simpleObjPtrField == NULL );
EXPECT_TRUE(demoObjs[0]->m_simpleObjPtrField2 != NULL );
// check single pointer field
std::vector<caf::PdmPointer<SimpleObj> > simpleObjs;
xmlErrorDoc.objectsByType(&simpleObjs);
EXPECT_EQ(size_t(1), simpleObjs.size() );
EXPECT_EQ(size_t(0), simpleObjs[0]->m_numbers().size());
}
}
//--------------------------------------------------------------------------------------------------
/// Tests the features of PdmPointer
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, PdmPointer)
{
caf::PdmDocument * d = new caf::PdmDocument;
{
caf::PdmPointer<caf::PdmDocument> p;
EXPECT_TRUE(p == NULL);
}
{
caf::PdmPointer<caf::PdmDocument> p(d);
caf::PdmPointer<caf::PdmDocument> p2(p);
EXPECT_TRUE(p == d && p2 == d);
EXPECT_TRUE(p.p() == d);
EXPECT_TRUE((*p).uiName() == (*d).uiName());
EXPECT_TRUE(p->uiName() == "File");
p = 0;
EXPECT_TRUE(p == NULL);
EXPECT_TRUE(p.isNull());
EXPECT_TRUE(p2 == d);
p = p2;
EXPECT_TRUE(p == d );
delete d;
EXPECT_TRUE(p.isNull() && p2.isNull());
}
caf::PdmPointer<DemoPdmObject> p3(new DemoPdmObject());
delete p3;
}
//--------------------------------------------------------------------------------------------------
/// Tests the PdmFactory
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, PdmObjectFactory)
{
{
SimpleObj* s = NULL;
s = dynamic_cast<SimpleObj*> (caf::PdmObjectFactory::instance()->create("SimpleObj"));
EXPECT_TRUE(s != NULL);
}
{
DemoPdmObject* s = NULL;
s = dynamic_cast<DemoPdmObject*> (caf::PdmObjectFactory::instance()->create("DemoPdmObject"));
EXPECT_TRUE(s != NULL);
delete s;
}
{
InheritedDemoObj* s = NULL;
s = dynamic_cast<InheritedDemoObj*> (caf::PdmObjectFactory::instance()->create("InheritedDemoObj"));
EXPECT_TRUE(s != NULL);
}
{
caf::PdmDocument* s = NULL;
s = dynamic_cast<caf::PdmDocument*> (caf::PdmObjectFactory::instance()->create("PdmDocument"));
EXPECT_TRUE(s != NULL);
}
{
caf::PdmObjectGroup* s = NULL;
s = dynamic_cast<caf::PdmObjectGroup*> (caf::PdmObjectFactory::instance()->create("PdmObjectGroup"));
EXPECT_TRUE(s != NULL);
}
}
//--------------------------------------------------------------------------------------------------
/// Validate Xml keywords
//--------------------------------------------------------------------------------------------------
TEST(BaseTest, ValidXmlKeywords)
{
EXPECT_TRUE(caf::PdmObject::isValidXmlElementName("Valid_name"));
EXPECT_FALSE(caf::PdmObject::isValidXmlElementName("2Valid_name"));
EXPECT_FALSE(caf::PdmObject::isValidXmlElementName(".Valid_name"));
EXPECT_FALSE(caf::PdmObject::isValidXmlElementName("xml_Valid_name"));
EXPECT_FALSE(caf::PdmObject::isValidXmlElementName("Valid_name_with_space "));
}
TEST(BaseTest, PdmPointersFieldInsertVector)
{
InheritedDemoObj* ihd1 = new InheritedDemoObj;
SimpleObj* s1 = new SimpleObj;
SimpleObj* s2 = new SimpleObj;
SimpleObj* s3 = new SimpleObj;
caf::PdmObjectGroup pdmGroup;
pdmGroup.addObject(s1);
pdmGroup.addObject(s2);
pdmGroup.addObject(s3);
std::vector<caf::PdmPointer<SimpleObj> > typedObjects;
pdmGroup.objectsByType(&typedObjects);
ihd1->m_simpleObjectsField.insert(ihd1->m_simpleObjectsField.size(), typedObjects);
EXPECT_EQ(size_t(3), ihd1->m_simpleObjectsField.size());
delete ihd1;
}
TEST(BaseTest, PdmObjectGroupCopyOfTypedObjects)
{
SimpleObj* s1 = new SimpleObj;
s1->m_position = 1000;
s1->m_numbers.v().push_back(10);
SimpleObj* s2 = new SimpleObj;
s2->m_position = 2000;
SimpleObj* s3 = new SimpleObj;
s3->m_position = 3000;
InheritedDemoObj* ihd1 = new InheritedDemoObj;
caf::PdmObjectGroup og;
og.objects.push_back(s1);
og.objects.push_back(s2);
og.objects.push_back(s3);
og.objects.push_back(ihd1);
std::vector<caf::PdmPointer<SimpleObj> > simpleObjList;
og.createCopyByType(&simpleObjList);
EXPECT_EQ(size_t(3), simpleObjList.size());
std::vector<caf::PdmPointer<InheritedDemoObj> > inheritObjList;
og.createCopyByType(&inheritObjList);
EXPECT_EQ(size_t(1), inheritObjList.size());
og.deleteObjects();
EXPECT_EQ(size_t(3), simpleObjList.size());
EXPECT_EQ(size_t(1), inheritObjList.size());
}

View File

@ -0,0 +1,56 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2013 Ceetron AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This library 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 at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library 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 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "gtest/gtest.h"
#include <stdio.h>
#include <iostream>
#include <string>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
char text[5];
std::cin.getline(text, 5);
return result;
}

View File

@ -0,0 +1,56 @@
cmake_minimum_required (VERSION 2.8)
project ( cafTestApplication )
# Qt MOC
set ( QT_MOC_HEADERS
MainWindow.h
WidgetLayoutTest.h
)
qt4_wrap_cpp( MOC_FILES_CPP
${QT_MOC_HEADERS}
)
# Resource file
set( QRC_FILES
textedit.qrc
)
# Runs RCC on specified files
qt4_add_resources( QRC_FILES_CPP
${QRC_FILES}
)
include_directories (
${CMAKE_SOURCE_DIR}/cafProjectDataModel
${CMAKE_SOURCE_DIR}/cafUserInterface
)
# add the executable
add_executable ( ${PROJECT_NAME}
Main.cpp
MainWindow.cpp
WidgetLayoutTest.cpp
${MOC_FILES_CPP}
${QRC_FILES_CPP}
)
target_link_libraries ( ${PROJECT_NAME}
cafUserInterface
cafProjectDataModel
${QT_LIBRARIES}
)
# Copy Qt Dlls
if (MSVC)
set (QTLIBLIST QtCore QtGui QtOpenGl)
foreach (qtlib ${QTLIBLIST})
# Debug
execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll)
# Release
execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll)
endforeach( qtlib )
endif(MSVC)

View File

@ -0,0 +1,15 @@
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.setWindowTitle("Ceetron Application Framework Test Application");
window.show();
return app.exec();
}

View File

@ -0,0 +1,418 @@
#include "MainWindow.h"
#include "WidgetLayoutTest.h"
#include <QDockWidget>
#include <QTreeView>
#include <QAction>
#include <QMenuBar>
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmDocument.h"
#include "cafAppEnum.h"
#include "cafUiTreeModelPdm.h"
#include "cafPdmUiPropertyView.h"
#include "cafPdmUiFilePathEditor.h"
#include "cafPdmUiListEditor.h"
#include "cafPdmUiTextEditor.h"
class DemoPdmObjectGroup: public caf::PdmObjectGroup
{
CAF_PDM_HEADER_INIT;
public:
DemoPdmObjectGroup()
{
CAF_PDM_InitObject("Demo Object Group", "", "This group object is a demo of the CAF framework", "This group object is a demo of the CAF framework")
}
};
CAF_PDM_SOURCE_INIT(DemoPdmObjectGroup, "DemoPdmObjectGroup");
class SmallDemoPdmObject: public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
SmallDemoPdmObject()
{
CAF_PDM_InitObject("Small Demo Object", ":/images/win/filenew.png", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework");
CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want" );
CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want");
CAF_PDM_InitField(&m_textField, "TextField", QString(""), "Text", "", "Text tooltip", "This is a place you can enter a small integer value if you want");
}
caf::PdmField<double> m_doubleField;
caf::PdmField<int> m_intField;
caf::PdmField<QString> m_textField;
};
CAF_PDM_SOURCE_INIT(SmallDemoPdmObject, "SmallDemoPdmObject");
class SmallDemoPdmObjectA: public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
enum TestEnumType
{
T1, T2, T3
};
SmallDemoPdmObjectA()
{
CAF_PDM_InitObject("Small Demo Object A", "", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework");
CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want");
CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here","This is a place you can enter a small integer value if you want");
CAF_PDM_InitField(&m_textField, "TextField", QString(""), "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want");
CAF_PDM_InitField(&m_testEnumField, "TestEnumValue", caf::AppEnum<TestEnumType>(T1), "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want");
m_testEnumField.setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName());
}
caf::PdmField<double> m_doubleField;
caf::PdmField<int> m_intField;
caf::PdmField<QString> m_textField;
caf::PdmField< caf::AppEnum<TestEnumType> > m_testEnumField;
};
CAF_PDM_SOURCE_INIT(SmallDemoPdmObjectA, "SmallDemoPdmObjectA");
namespace caf
{
template<>
void AppEnum<SmallDemoPdmObjectA::TestEnumType>::setUp()
{
addItem(SmallDemoPdmObjectA::T1, "T1", "An A letter");
addItem(SmallDemoPdmObjectA::T2, "T2", "A B letter");
addItem(SmallDemoPdmObjectA::T3, "T3", "A B C letter");
setDefault(SmallDemoPdmObjectA::T1);
}
}
Q_DECLARE_METATYPE(caf::AppEnum<SmallDemoPdmObjectA::TestEnumType>);
class DemoPdmObject: public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
DemoPdmObject()
{
CAF_PDM_InitObject( "Demo Object", "", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework");
CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want");
CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want" );
CAF_PDM_InitField(&m_boolField, "BooleanValue", false, "Boolean:" , "", "Boolean:Enter some small number here", "Boolean:This is a place you can enter a small integer value if you want");
CAF_PDM_InitField(&m_textField, "TextField", QString(""), "", "", "", "");
CAF_PDM_InitField(&m_filePath, "FilePath", QString(""), "Filename", "", "", "");
CAF_PDM_InitField(&m_longText, "LongText", QString("Test text"), "Long Text", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_multiSelectList, "MultiSelect", "Selection List", "", "List" , "This is a multi selection list" );
CAF_PDM_InitFieldNoDefault(&m_objectList, "ObjectList", "Objects list", "", "List" , "This is a list of PdmObjects" );
m_filePath.setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName());
m_filePath.setUiLabelPosition(caf::PdmUiItemInfo::TOP);
m_longText.setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName());
m_longText.setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering)
{
uiOrdering.add(&m_boolField);
caf::PdmUiGroup* group1 = uiOrdering.addNewGroup("Name1");
group1->add(&m_doubleField);
caf::PdmUiGroup* group2 = uiOrdering.addNewGroup("Name2");
group2->add(&m_intField);
caf::PdmUiGroup* group3 = group2->addNewGroup("Name3");
group3->add(&m_textField);
//uiConfig->add(&f3);
//uiConfig->forgetRemainingFields();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
virtual QList<caf::PdmOptionItemInfo> calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly)
{
QList<caf::PdmOptionItemInfo> options;
if (&m_multiSelectList == fieldNeedingOptions)
{
options.push_back(caf::PdmOptionItemInfo("Choice 1", "Choice1"));
options.push_back(caf::PdmOptionItemInfo("Choice 2", "Choice2"));
options.push_back(caf::PdmOptionItemInfo("Choice 3", "Choice3"));
options.push_back(caf::PdmOptionItemInfo("Choice 4", "Choice4"));
options.push_back(caf::PdmOptionItemInfo("Choice 5", "Choice5"));
options.push_back(caf::PdmOptionItemInfo("Choice 6", "Choice6"));
}
if (useOptionsOnly) *useOptionsOnly = true;
return options;
}
// Fields
caf::PdmField<bool> m_boolField;
caf::PdmField<double> m_doubleField;
caf::PdmField<int> m_intField;
caf::PdmField<QString> m_textField;
caf::PdmField<QString> m_filePath;
caf::PdmField<QString> m_longText;
caf::PdmField<std::vector<QString> > m_multiSelectList;
caf::PdmPointersField< caf::PdmObject* > m_objectList;
};
CAF_PDM_SOURCE_INIT(DemoPdmObject, "DemoPdmObject");
MainWindow* MainWindow::sm_mainWindowInstance = NULL;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
MainWindow::MainWindow()
{
m_treeView = NULL;
m_treeModelPdm = NULL;
createActions();
createDockPanels();
buildTestModel();
setPdmRoot(m_testRoot);
sm_mainWindowInstance = this;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::createDockPanels()
{
{
QDockWidget* dockWidget = new QDockWidget("Workspace", this);
dockWidget->setObjectName("dockWidget");
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_treeView = new QTreeView(dockWidget);
dockWidget->setWidget(m_treeView);
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
}
/*
{
QDockWidget* dockWidget = new QDockWidget("WidgetLayoutTest", this);
dockWidget->setObjectName("dockWidget");
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
WidgetLayoutTest* widgetLayoutTest = new WidgetLayoutTest(dockWidget);
dockWidget->setWidget(widgetLayoutTest);
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
}
*/
{
QDockWidget* dockWidget = new QDockWidget("cafPropertyView", this);
dockWidget->setObjectName("dockWidget");
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pdmUiPropertyView = new caf::PdmUiPropertyView(dockWidget);
dockWidget->setWidget(m_pdmUiPropertyView);
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::buildTestModel()
{
m_testRoot = new DemoPdmObjectGroup;
DemoPdmObject* demoObject = new DemoPdmObject;
m_testRoot->addObject(demoObject);
SmallDemoPdmObject* smallObj1 = new SmallDemoPdmObject;
m_testRoot->addObject(smallObj1);
SmallDemoPdmObjectA* smallObj2 = new SmallDemoPdmObjectA;
m_testRoot->addObject(smallObj2);
demoObject->m_objectList.push_back(new DemoPdmObject);
demoObject->m_objectList.push_back(new SmallDemoPdmObjectA());
demoObject->m_objectList.push_back(new SmallDemoPdmObject());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::setPdmRoot(caf::PdmObject* pdmRoot)
{
caf::PdmUiTreeItem* treeItemRoot = caf::UiTreeItemBuilderPdm::buildViewItems(NULL, 0, pdmRoot);
if (!m_treeModelPdm)
{
m_treeModelPdm = new caf::UiTreeModelPdm(this);
}
m_treeModelPdm->setTreeItemRoot(treeItemRoot);
assert(m_treeView);
m_treeView->setModel(m_treeModelPdm);
if (treeItemRoot)
{
if (m_treeView->selectionModel())
{
connect(m_treeView->selectionModel(), SIGNAL(selectionChanged( const QItemSelection & , const QItemSelection & )), SLOT(slotSelectionChanged( const QItemSelection & , const QItemSelection & )));
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
MainWindow::~MainWindow()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::releaseTestData()
{
m_treeView->setModel(NULL);
if (m_treeModelPdm)
{
delete m_treeModelPdm;
}
if (m_testRoot)
{
m_testRoot->deleteObjects();
delete m_testRoot;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
MainWindow* MainWindow::instance()
{
return sm_mainWindowInstance;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::createActions()
{
// Create actions
QAction* editInsert = new QAction("&Insert", this);
QAction* editRemove = new QAction("&Remove", this);
QAction* editRemoveAll = new QAction("Remove all", this);
connect(editInsert, SIGNAL(triggered()), SLOT(slotInsert()));
connect(editRemove, SIGNAL(triggered()), SLOT(slotRemove()));
connect(editRemoveAll, SIGNAL(triggered()), SLOT(slotRemoveAll()));
// Create menus
QMenu* editMenu = menuBar()->addMenu("&Edit");
editMenu->addAction(editInsert);
editMenu->addAction(editRemove);
editMenu->addAction(editRemoveAll);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::slotInsert()
{
QModelIndex index = m_treeView->selectionModel()->currentIndex();
QAbstractItemModel *model = m_treeView->model();
if (!model->insertRow(0, index))
return;
QModelIndex child = model->index(0, 0, index);
// (
// for (int column = 0; column < model->columnCount(index); ++column)
// {
// QModelIndex child = model->index(0, column, index);
// model->setData(child, QVariant("[No data]"), Qt::EditRole);
// if (!model->headerData(column, Qt::Horizontal).isValid())
// model->setHeaderData(column, Qt::Horizontal, QVariant("[No header]"),
// Qt::EditRole);
// }
// )
m_treeView->selectionModel()->setCurrentIndex(model->index(0, 0, index), QItemSelectionModel::ClearAndSelect);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::slotRemove()
{
QModelIndex index = m_treeView->selectionModel()->currentIndex();
QAbstractItemModel *model = m_treeView->model();
model->removeRow(index.row(), index.parent());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::slotRemoveAll()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MainWindow::slotSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected )
{
if (selected.indexes().size() == 1)
{
QModelIndex mi = selected.indexes()[0];
caf::PdmUiTreeItem* treeItem = m_treeModelPdm->getTreeItemFromIndex(mi);
if (treeItem && treeItem->dataObject())
{
m_pdmUiPropertyView->showProperties(treeItem->dataObject());
}
}
else
{
m_pdmUiPropertyView->showProperties(NULL);
}
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <QtGui/QMainWindow>
#include <QAbstractItemModel>
#include <QItemSelection>
class DemoPdmObject;
class QTreeView;
namespace caf
{
class PdmObjectGroup;
class PdmObject;
class UiTreeModelPdm;
class PdmUiPropertyView;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
~MainWindow();
static MainWindow* instance();
void setPdmRoot(caf::PdmObject* pdmRoot);
private:
void createActions();
void createMenus();
void createToolBars();
void createDockPanels();
void buildTestModel();
void releaseTestData();
private slots:
void slotInsert();
void slotRemove();
void slotRemoveAll();
void slotSelectionChanged(const QItemSelection &, const QItemSelection & );
private:
static MainWindow* sm_mainWindowInstance;
private:
QTreeView* m_treeView;
caf::UiTreeModelPdm* m_treeModelPdm;
caf::PdmUiPropertyView* m_pdmUiPropertyView;
caf::PdmObjectGroup* m_testRoot;
};

View File

@ -0,0 +1,108 @@
#include "WidgetLayoutTest.h"
#include <QGridLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QGroupBox>
#include <QLabel>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
WidgetLayoutTest::WidgetLayoutTest(QWidget* parent /*= 0*/, Qt::WindowFlags f /*= 0*/)
: QWidget(parent, f)
{
QVBoxLayout* l = new QVBoxLayout;
setLayout(l);
{
QPushButton* b1 = new QPushButton("Original config", this);
connect(b1, SIGNAL(clicked()), SLOT(setUpInitialConfiguration()));
l->addWidget(b1);
}
{
QPushButton* b1 = new QPushButton("Config A", this);
connect(b1, SIGNAL(clicked()), SLOT(setUpInitialConfigurationA()));
l->addWidget(b1);
}
{
QPushButton* b1 = new QPushButton("Config B", this);
connect(b1, SIGNAL(clicked()), SLOT(setUpInitialConfigurationB()));
l->addWidget(b1);
}
m_mainLayout = new QGridLayout();
l->addLayout(m_mainLayout);
// Create widgets
m_widget1 = new QLineEdit("1", this);
m_widget2 = new QLineEdit("2", this);
m_widget3 = new QLineEdit("3", this);
m_widget4 = new QLineEdit("4", this);
m_widget5 = new QLineEdit("5", this);
m_groupBoxA = new QGroupBox("Groupbox A", this);
m_groupBoxALayout = new QGridLayout();
m_groupBoxA->setLayout(m_groupBoxALayout);
m_groupBoxB = new QGroupBox("Groupbox B", this);
m_groupBoxBLayout = new QGridLayout();
m_groupBoxB->setLayout(m_groupBoxBLayout);
setUpInitialConfiguration();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
WidgetLayoutTest::~WidgetLayoutTest()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void WidgetLayoutTest::setUpInitialConfiguration()
{
m_mainLayout->addWidget(m_widget1);
m_mainLayout->addWidget(m_groupBoxA);
m_groupBoxALayout->addWidget(m_widget2, 0, 0);
if (!m_widget3)
{
m_widget3 = new QLabel("Test label", this);
}
m_groupBoxALayout->addWidget(m_widget3, 1, 0);
m_groupBoxALayout->addWidget(m_groupBoxB, 2, 0);
m_groupBoxBLayout->addWidget(m_widget4);
m_mainLayout->addWidget(m_widget5);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void WidgetLayoutTest::setUpInitialConfigurationA()
{
m_mainLayout->addWidget(m_widget2);
delete m_widget3;
m_widget3 = NULL;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void WidgetLayoutTest::setUpInitialConfigurationB()
{
m_mainLayout->addWidget(m_widget4);
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <QtGui/QWidget>
class QGridLayout;
class QGroupBox;
class WidgetLayoutTest : public QWidget
{
Q_OBJECT
public:
WidgetLayoutTest(QWidget* parent = 0, Qt::WindowFlags f = 0);
~WidgetLayoutTest();
private:
QGridLayout* m_mainLayout;
QGroupBox* m_groupBoxA;
QGridLayout* m_groupBoxALayout;
QGroupBox* m_groupBoxB;
QGridLayout* m_groupBoxBLayout;
QWidget* m_widget1;
QWidget* m_widget2;
QWidget* m_widget3;
QWidget* m_widget4;
QWidget* m_widget5;
private slots:
void setUpInitialConfiguration();
void setUpInitialConfigurationA();
void setUpInitialConfigurationB();
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,43 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>images/logo32.png</file>
<file>images/mac/editcopy.png</file>
<file>images/mac/editcut.png</file>
<file>images/mac/editpaste.png</file>
<file>images/mac/editredo.png</file>
<file>images/mac/editundo.png</file>
<file>images/mac/exportpdf.png</file>
<file>images/mac/filenew.png</file>
<file>images/mac/fileopen.png</file>
<file>images/mac/fileprint.png</file>
<file>images/mac/filesave.png</file>
<file>images/mac/textbold.png</file>
<file>images/mac/textcenter.png</file>
<file>images/mac/textitalic.png</file>
<file>images/mac/textjustify.png</file>
<file>images/mac/textleft.png</file>
<file>images/mac/textright.png</file>
<file>images/mac/textunder.png</file>
<file>images/mac/zoomin.png</file>
<file>images/mac/zoomout.png</file>
<file>images/win/editcopy.png</file>
<file>images/win/editcut.png</file>
<file>images/win/editpaste.png</file>
<file>images/win/editredo.png</file>
<file>images/win/editundo.png</file>
<file>images/win/exportpdf.png</file>
<file>images/win/filenew.png</file>
<file>images/win/fileopen.png</file>
<file>images/win/fileprint.png</file>
<file>images/win/filesave.png</file>
<file>images/win/textbold.png</file>
<file>images/win/textcenter.png</file>
<file>images/win/textitalic.png</file>
<file>images/win/textjustify.png</file>
<file>images/win/textleft.png</file>
<file>images/win/textright.png</file>
<file>images/win/textunder.png</file>
<file>images/win/zoomin.png</file>
<file>images/win/zoomout.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,43 @@
namespace cvftest {
//==================================================================================================
//
//
//==================================================================================================
class Utils
{
public:
static cvf::String getTestDataDir(const cvf::String& unitTestFolder)
{
#ifdef WIN32
std::string exe = std::string(testing::internal::GetArgvs()[0]);
#else
std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString());
std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]);
#endif
std::string testPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("TestData/");
return testPath;
}
static cvf::String getGLSLDir(const cvf::String& unitTestFolder)
{
#ifdef WIN32
std::string exe = std::string(testing::internal::GetArgvs()[0]);
#else
std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString());
std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]);
#endif
std::string glslPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("../LibRender/glsl/");
return glslPath;
}
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -159,6 +159,7 @@ LocatorPanWalkRotate::LocatorPanWalkRotate(Camera* camera)
: m_camera(camera),
m_operation(PAN),
m_pos(0, 0, 0),
m_rotQuat(0, 0, 0, 1),
m_lastPosX(0),
m_lastPosY(0)
{
@ -202,6 +203,24 @@ Vec3d LocatorPanWalkRotate::position() const
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::setOrientation(const Mat3d& m)
{
m_rotQuat = Quatd::fromRotationMatrix(Mat4d(m));
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Mat3d LocatorPanWalkRotate::orientation() const
{
return m_rotQuat.toMatrix3();
}
//--------------------------------------------------------------------------------------------------
/// The window coordinates are in OpenGL style coordinates, which means a right handed
/// coordinate system with the origin in the lower left corner of the window.
@ -221,31 +240,39 @@ bool LocatorPanWalkRotate::update(int x, int y)
{
CVF_ASSERT(m_camera.notNull());
if (x == m_lastPosX && y == m_lastPosY) return false;
if (x == m_lastPosX && y == m_lastPosY)
{
return false;
}
const double vpPixSizeX = m_camera->viewport()->width();
const double vpPixSizeY = m_camera->viewport()->height();
if (vpPixSizeX <= 0 || vpPixSizeY <= 0) return false;
// Need a non-zero viewport
if (m_camera->viewport()->width() <= 0 ||
m_camera->viewport()->height() <= 0)
{
return false;
}
// Normalized movement in screen plane
const double tx = (x - m_lastPosX)/vpPixSizeX;
const double ty = (y - m_lastPosY)/vpPixSizeY;
Vec3d oldPos = m_pos;
Quatd oldRotQuat = m_rotQuat;
if (m_operation == PAN)
{
updatePan(tx, ty);
updatePan(x, y);
}
else if (m_operation == WALK)
{
updateWalk(ty);
updateWalk(y);
}
else if (m_operation == ROTATE)
{
updateRotation(x, y);
}
m_lastPosX = x;
m_lastPosY = y;
if (m_pos == oldPos)
if (m_pos == oldPos && m_rotQuat == oldRotQuat)
{
return false;
}
@ -259,10 +286,17 @@ bool LocatorPanWalkRotate::update(int x, int y)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::updatePan(double tx, double ty)
void LocatorPanWalkRotate::updatePan(int oglWinCoordX, int oglWinCoordY)
{
CVF_ASSERT(m_camera.notNull());
// Normalized movement in screen plane [0, 1]
const double vpPixSizeX = m_camera->viewport()->width();
const double vpPixSizeY = m_camera->viewport()->height();
CVF_ASSERT(vpPixSizeX > 0 && vpPixSizeY > 0);
const double tx = (oglWinCoordX - m_lastPosX)/vpPixSizeX;
const double ty = (oglWinCoordY - m_lastPosY)/vpPixSizeY;
// Viewport size in world coordinates
const double aspect = m_camera->aspectRatio();
const double vpWorldSizeY = m_camera->frontPlaneFrustumHeight();
@ -303,10 +337,15 @@ void LocatorPanWalkRotate::updatePan(double tx, double ty)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::updateWalk(double ty)
void LocatorPanWalkRotate::updateWalk(int oglWinCoordY)
{
CVF_ASSERT(m_camera.notNull());
// Normalized movement in screen plane [0, 1]
const double vpPixSizeY = m_camera->viewport()->height();
CVF_ASSERT(vpPixSizeY > 0);
const double ty = (oglWinCoordY - m_lastPosY)/vpPixSizeY;
const double vpWorldSizeY = m_camera->frontPlaneFrustumHeight();
const Vec3d camDir = m_camera->direction();
@ -337,5 +376,127 @@ void LocatorPanWalkRotate::updateWalk(double ty)
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void LocatorPanWalkRotate::updateRotation(int oglWinCoordX, int oglWinCoordY)
{
CVF_ASSERT(m_camera.notNull());
const double vpPixSizeX = m_camera->viewport()->width();
const double vpPixSizeY = m_camera->viewport()->height();
CVF_ASSERT(vpPixSizeX > 0 && vpPixSizeY > 0);
// Scale the new/last positions to the range [-1.0, 1.0]
const double newPosX = 2.0*(oglWinCoordX/vpPixSizeX) - 1.0;
const double newPosY = 2.0*((vpPixSizeY - oglWinCoordY)/vpPixSizeY) - 1.0;
const double oldPosX = 2.0*(m_lastPosX/vpPixSizeX) - 1.0;
const double oldPosY = 2.0*((vpPixSizeY - m_lastPosY)/vpPixSizeY) - 1.0;
// For now, use hard-coded value for trackball radius and sensitivity
// Sensitivity could be exposed directly, but trackball rotation needs more consideration.
// An idea would be for the user to be able to set an approximate size of the locator's visual representation in world coords,
// and then we could estimate its current size relative to viewport, and then use that as trackball radius.
// See trackballRotation() for some more info on trackballRadius (we've always used 0.8 as an approximation)
const double trackballRadius = 0.8;
const double rotateSensitivity = 1.0;
Mat4d viewMat = m_camera->viewMatrix();
Quatd incrementalRotationQuat = trackballRotation(oldPosX, -oldPosY, newPosX, -newPosY, viewMat, trackballRadius, rotateSensitivity);
// Update rotation quaternion
Mat4d incRotationMatrix = incrementalRotationQuat.toMatrix4();
incRotationMatrix.translatePostMultiply(-m_pos);
incRotationMatrix.translatePreMultiply(m_pos);
Mat4d rotMat = m_rotQuat.toMatrix4();
rotMat = incRotationMatrix*rotMat;
m_rotQuat = Quatd::fromRotationMatrix(rotMat);
}
//--------------------------------------------------------------------------------------------------
/// Compute quaternion rotation
///
/// \param oldPosX x coordinate of the last position of the mouse, in the range [-1.0, 1.0]
/// \param oldPosY y coordinate of the last position of the mouse, in the range [-1.0, 1.0]
/// \param newPosX x coordinate of current position of the mouse, in the range [-1.0, 1.0]
/// \param newPosY y coordinate of current position of the mouse, in the range [-1.0, 1.0]
/// \param currViewMatrix Current transformation matrix. The inverse is used when calculating the rotation
/// \param sensitivityFactor Mouse sensitivity factor
///
/// Simulate a track-ball. Project the points onto the virtual trackball, then figure out the axis
/// of rotation. This is a deformed trackball-- is a trackball in the center, but is deformed into a
/// hyperbolic sheet of rotation away from the center.
//--------------------------------------------------------------------------------------------------
Quatd LocatorPanWalkRotate::trackballRotation(double oldPosX, double oldPosY, double newPosX, double newPosY, const Mat4d& currViewMatrix, double trackballRadius, double sensitivityFactor)
{
// This particular function was chosen after trying out several variations.
// Implemented by Gavin Bell, lots of ideas from Thant Tessman and the August '88
// issue of Siggraph's "Computer Graphics," pp. 121-129.
// This size should really be based on the distance from the center of rotation to the point on
// the object underneath the mouse. That point would then track the mouse as closely as possible.
//const double TRACKBALL_RADIUS = 0.8f;
// Clamp to valid range
oldPosX = Math::clamp(oldPosX, -1.0, 1.0);
oldPosY = Math::clamp(oldPosY, -1.0, 1.0);
newPosX = Math::clamp(newPosX, -1.0, 1.0);
newPosY = Math::clamp(newPosY, -1.0, 1.0);
// First, figure out z-coordinates for projection of P1 and P2 to deformed sphere
Vec3d p1 = projectToSphere(trackballRadius, oldPosX, oldPosY);
Vec3d p2 = projectToSphere(trackballRadius, newPosX, newPosY);
// Axis of rotation is the cross product of P1 and P2
Vec3d a = p1 ^ p2;
// Figure out how much to rotate around that axis.
Vec3d d = p1 - p2;
double t = d.length()/(2.0*trackballRadius);
// Avoid problems with out-of-control values...
t = Math::clamp(t, -1.0, 1.0);
double phi = 2.0*Math::asin(t);
// Scale by sensitivity factor
phi *= sensitivityFactor;
// Use inverted matrix to find rotation axis
Mat4d invMatr = currViewMatrix.getInverted();
a.transformVector(invMatr);
// Get quaternion to be returned by pointer
Quatd quat = Quatd::fromAxisAngle(a, phi);
return quat;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Vec3d LocatorPanWalkRotate::projectToSphere(double radius, double posX, double posY)
{
double d = Math::sqrt(posX*posX + posY*posY);
if (d < radius*SQRT1_2_D)
{
// Inside sphere
double projectedZ = Math::sqrt(radius*radius - d*d);
return Vec3d(posX, posY, projectedZ);
}
else
{
// On hyperbola
double t = radius/SQRT2_D;
double projectedZ = t*t/d;
return Vec3d(posX, posY, projectedZ);
}
}
} // namespace cvf

View File

@ -38,6 +38,7 @@
#pragma once
#include "cvfPlane.h"
#include "cvfQuat.h"
namespace cvf {
@ -97,8 +98,8 @@ public:
enum Operation
{
PAN,
WALK
//ROTATE // TODO
WALK,
ROTATE
};
public:
@ -106,20 +107,29 @@ public:
~LocatorPanWalkRotate();
void setOperation(Operation op);
void setPosition(const Vec3d& position);
virtual Vec3d position() const;
void setOrientation(const Mat3d& m);
Mat3d orientation() const;
virtual void start(int x, int y);
virtual bool update(int x, int y);
private:
void updatePan(double tx, double ty);
void updateWalk(double ty);
void updatePan(int oglWinCoordX, int oglWinCoordY);
void updateWalk(int oglWinCoordY);
void updateRotation(int oglWinCoordX, int oglWinCoordY);
static Quatd trackballRotation(double oldPosX, double oldPosY, double newPosX, double newPosY, const Mat4d& currViewMatrix, double trackballRadius, double sensitivityFactor);
static Vec3d projectToSphere(double radius, double posX, double posY);
private:
ref<Camera> m_camera;
Operation m_operation; // Default operation is PAN
Vec3d m_pos;
int m_lastPosX;
Quatd m_rotQuat;
int m_lastPosX; // Last position, window coords, origin lower left (OpenGL style)
int m_lastPosY;
};

View File

@ -40,7 +40,6 @@
#include "cvfCamera.h"
#include "cvfViewport.h"
#include <cmath>
#include <cstdlib>
namespace cvf {
@ -296,7 +295,7 @@ bool ManipulatorTrackball::zoom(int posX, int posY)
Camera::ProjectionType projType = m_camera->projection();
if (projType == Camera::PERSPECTIVE)
{
double fovY = 2*atan((newFrustumHeight/2)/nearPlane);
double fovY = 2*Math::atan((newFrustumHeight/2)/nearPlane);
if (fovY > 0)
{
m_camera->setProjectionAsPerspective(Math::toDegrees(fovY), nearPlane, farPlane);
@ -407,7 +406,7 @@ Quatd ManipulatorTrackball::trackballRotation(double oldPosX, double oldPosY, do
// Avoid problems with out-of-control values...
t = Math::clamp(t, -1.0, 1.0);
double phi = 2.0*asin(t);
double phi = 2.0*Math::asin(t);
// Scale by sensitivity factor
phi *= sensitivityFactor;
@ -437,12 +436,12 @@ Quatd ManipulatorTrackball::trackballRotation(double oldPosX, double oldPosY, do
//--------------------------------------------------------------------------------------------------
Vec3d ManipulatorTrackball::projectToSphere(double radius, double posX, double posY)
{
double d = sqrt(posX*posX + posY*posY);
double d = Math::sqrt(posX*posX + posY*posY);
if (d < radius*SQRT1_2_D)
{
// Inside sphere
double projectedZ = sqrt(radius*radius - d*d);
double projectedZ = Math::sqrt(radius*radius - d*d);
return Vec3d(posX, posY, projectedZ);
}

View File

@ -231,9 +231,20 @@ void Manipulators::onPaintEvent(PostEventAction* postEventAction)
m_camera->applyOpenGL();
GeometryBuilderDrawableGeo builder;
GeometryUtils::createBox(Vec3f(m_activeLocator->position()), 0.2f, 0.2f, 0.2f, &builder);
GeometryUtils::createBox(Vec3f::ZERO, 0.2f, 0.2f, 0.2f, &builder);
ref<DrawableGeo> boxGeo = builder.drawableGeo();
Mat4d transform;
if (dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p()))
{
LocatorPanWalkRotate* loc = dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p());
transform.setFromMatrix3(loc->orientation());
}
transform.translatePreMultiply(m_activeLocator->position());
boxGeo->transform(transform);
boxGeo->computeNormals();
RenderStateLighting_FF lighting;
@ -262,15 +273,19 @@ void Manipulators::onMousePressEvent(MouseButton buttonPressed, MouseEvent* mous
if (dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p()))
{
LocatorPanWalkRotate* loc = dynamic_cast<LocatorPanWalkRotate*>(m_activeLocator.p());
if (mouseEvent->buttons() == MiddleButton ||
mouseEvent->buttons() == (LeftButton | RightButton))
{
loc->setOperation(LocatorPanWalkRotate::WALK);
}
else
if (mouseEvent->buttons() == LeftButton)
{
loc->setOperation(LocatorPanWalkRotate::PAN);
}
else if (mouseEvent->buttons() == RightButton)
{
loc->setOperation(LocatorPanWalkRotate::ROTATE);
}
else if (mouseEvent->buttons() == MiddleButton ||
mouseEvent->buttons() == (LeftButton | RightButton))
{
loc->setOperation(LocatorPanWalkRotate::WALK);
}
}
m_activeLocator->start(x, y);
@ -293,9 +308,10 @@ void Manipulators::onMouseMoveEvent(MouseEvent* mouseEvent)
{
int x = mouseEvent->x();
int y = mouseEvent->y();
m_activeLocator->update(x, y);
mouseEvent->setRequestedAction(REDRAW);
if (m_activeLocator->update(x, y))
{
mouseEvent->setRequestedAction(REDRAW);
}
return;
}