Compare commits
226
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bcdf2e4dc | ||
|
|
cd5a720211 | ||
|
|
5cb04946b0 | ||
|
|
c8953c6275 | ||
|
|
e8dc9c9454 | ||
|
|
a0c325681f | ||
|
|
8d3bf19422 | ||
|
|
4477867ef4 | ||
|
|
e696c884dc | ||
|
|
80bcaa49e6 | ||
|
|
0096c1bb02 | ||
|
|
38b37a068d | ||
|
|
0281f31df2 | ||
|
|
40b182c550 | ||
|
|
d1dedc7511 | ||
|
|
04cd9b3eb6 | ||
|
|
de6003367d | ||
|
|
a5f42eeddf | ||
|
|
a8ba041b67 | ||
|
|
e700fc6f34 | ||
|
|
af29d3d257 | ||
|
|
487701a143 | ||
|
|
f32e037c58 | ||
|
|
8bd903dd96 | ||
|
|
560c100484 | ||
|
|
52444d177b | ||
|
|
b4f7ff29ef | ||
|
|
f7c6a5bfa2 | ||
|
|
6fe14f7a6b | ||
|
|
786e5addd8 | ||
|
|
2e9a15f523 | ||
|
|
bb0d2ddc53 | ||
|
|
702fb014a5 | ||
|
|
834eab9457 | ||
|
|
a85da04601 | ||
|
|
414f1c27e4 | ||
|
|
c76e2eb900 | ||
|
|
c523e15302 | ||
|
|
2dc8de295d | ||
|
|
d645fd6327 | ||
|
|
219a7f3a07 | ||
|
|
d95e3e0055 | ||
|
|
2cc31ff425 | ||
|
|
8258fd7d9f | ||
|
|
784cca2233 | ||
|
|
436539a700 | ||
|
|
dcb3da9f28 | ||
|
|
a354c841f1 | ||
|
|
3824f064cd | ||
|
|
cba6db752b | ||
|
|
a458e26581 | ||
|
|
9d68727a84 | ||
|
|
38b9a874e0 | ||
|
|
7a680fb9f2 | ||
|
|
a5f9262adb | ||
|
|
b05e32fa8c | ||
|
|
53d8cff835 | ||
|
|
00fe97ff88 | ||
|
|
607511fd64 | ||
|
|
8663c265d8 | ||
|
|
6c5d35d6ce | ||
|
|
95532cb318 | ||
|
|
4d91bc5908 | ||
|
|
b13900402d | ||
|
|
1bb6c03bd0 | ||
|
|
1445949e31 | ||
|
|
360d3834ca | ||
|
|
aacdcad529 | ||
|
|
ad9341835f | ||
|
|
b028adb6af | ||
|
|
39f683b272 | ||
|
|
a6c46c89eb | ||
|
|
d534cf6f02 | ||
|
|
dd4326f7c4 | ||
|
|
40aecd688e | ||
|
|
63730a6e2c | ||
|
|
4d4d26aef8 | ||
|
|
de6b32d8c6 | ||
|
|
a0af7f0524 | ||
|
|
c043bd3422 | ||
|
|
18ae1d6940 | ||
|
|
d6f64f9773 | ||
|
|
db99a4cb90 | ||
|
|
108689661f | ||
|
|
d3e00dba8e | ||
|
|
fcd33e5035 | ||
|
|
af9082cd9f | ||
|
|
6a0bb18fca | ||
|
|
8aa8d87781 | ||
|
|
4998af8d7a | ||
|
|
c6aa95f3f3 | ||
|
|
481be29366 | ||
|
|
3617b6ad8c | ||
|
|
3fb8e19a38 | ||
|
|
2ea2f1b4f2 | ||
|
|
26cb8ec4f1 | ||
|
|
7fe56bea86 | ||
|
|
11b16b8a86 | ||
|
|
de020ee695 | ||
|
|
3b83487611 | ||
|
|
09bab4f162 | ||
|
|
49fcc799ca | ||
|
|
10bc803775 | ||
|
|
4f40770fc6 | ||
|
|
a4495c6ef1 | ||
|
|
67d837c4ec | ||
|
|
138825af6d | ||
|
|
c093841336 | ||
|
|
2df1da4226 | ||
|
|
2792d60e2d | ||
|
|
656a3ace07 | ||
|
|
aec8e88c14 | ||
|
|
bdd5ca140d | ||
|
|
8b3b0def03 | ||
|
|
6440ece177 | ||
|
|
bd3518637c | ||
|
|
aef2a1c484 | ||
|
|
a4b28e5737 | ||
|
|
a3bc2eb836 | ||
|
|
3059da5805 | ||
|
|
18d5a492c8 | ||
|
|
160b0ea7d9 | ||
|
|
4dd1267bea | ||
|
|
b5c4328682 | ||
|
|
571fc69ef4 | ||
|
|
f51595cfc9 | ||
|
|
d54aea0036 | ||
|
|
51bb2974bc | ||
|
|
7a859061fd | ||
|
|
cefa9fcd75 | ||
|
|
d3bacd0b73 | ||
|
|
b94a98fc90 | ||
|
|
e0b2687231 | ||
|
|
cc6179a4dd | ||
|
|
e947bac4a3 | ||
|
|
11ecbb6ca7 | ||
|
|
322789cd4c | ||
|
|
f28464dba0 | ||
|
|
8f6456b1f8 | ||
|
|
1f32786c82 | ||
|
|
829c729ee9 | ||
|
|
5d3aacb892 | ||
|
|
741e9c5ed5 | ||
|
|
1408c1b623 | ||
|
|
c256f8d09e | ||
|
|
55c018c525 | ||
|
|
3fa94b5143 | ||
|
|
5127e2f89c | ||
|
|
3175fa3aca | ||
|
|
5614174b39 | ||
|
|
39fc52fe0a | ||
|
|
81188705b1 | ||
|
|
63c4873d8a | ||
|
|
1a85dcd890 | ||
|
|
27470fc504 | ||
|
|
65d18445d3 | ||
|
|
84dd54b33a | ||
|
|
7c410d36e3 | ||
|
|
98a603a570 | ||
|
|
5876052170 | ||
|
|
f8303b4623 | ||
|
|
20005a7a22 | ||
|
|
4f0bfbab21 | ||
|
|
811442832e | ||
|
|
40811311d7 | ||
|
|
198de211f8 | ||
|
|
9f5412fa9d | ||
|
|
0dc9de81ae | ||
|
|
5b8f42ce5e | ||
|
|
5314274ed6 | ||
|
|
c831856711 | ||
|
|
1bade6d796 | ||
|
|
629a4a950e | ||
|
|
aebb1f6ec8 | ||
|
|
6e42bc55e0 | ||
|
|
1235fba7ee | ||
|
|
7a459db022 | ||
|
|
607987def5 | ||
|
|
397ec62180 | ||
|
|
9315210fbe | ||
|
|
5127990a43 | ||
|
|
40ad2b155a | ||
|
|
a0412d026c | ||
|
|
7d2134c488 | ||
|
|
d894f52b97 | ||
|
|
735f475c24 | ||
|
|
353dd73e24 | ||
|
|
49fe06498a | ||
|
|
bc95ec8084 | ||
|
|
f79906bf16 | ||
|
|
b3262fcb80 | ||
|
|
52b8f924aa | ||
|
|
52f57160aa | ||
|
|
6d4f23919c | ||
|
|
899623f71b | ||
|
|
c5d677ac7b | ||
|
|
c75270a9fc | ||
|
|
1588a379eb | ||
|
|
72d2075828 | ||
|
|
e99c682637 | ||
|
|
c815f70831 | ||
|
|
0da50eaa79 | ||
|
|
b0af84a549 | ||
|
|
b9631e8521 | ||
|
|
f664f7a201 | ||
|
|
f72b3882c3 | ||
|
|
ea47a2973c | ||
|
|
04be9ca670 | ||
|
|
6f0baf6ca9 | ||
|
|
1f5ec6b8d5 | ||
|
|
a2a91520aa | ||
|
|
fd7b5d3de7 | ||
|
|
30ea844c43 | ||
|
|
efac53b121 | ||
|
|
73c0ef59c1 | ||
|
|
7e65ab2d3b | ||
|
|
fec769f632 | ||
|
|
90e42642b6 | ||
|
|
9d9610a882 | ||
|
|
1fc81f4b66 | ||
|
|
4f0b1e847c | ||
|
|
9567ac32f2 | ||
|
|
8dd9cfa2a6 | ||
|
|
dbda8ef893 | ||
|
|
cd143c15d5 | ||
|
|
509a388ccc |
+1
-1
@@ -4,7 +4,7 @@ EXTRA_DIST = \
|
||||
DoxygenMain.cxx \
|
||||
README.MSVC \
|
||||
README.zlib \
|
||||
projects \
|
||||
projects \
|
||||
SimGear.dsp \
|
||||
SimGear.dsw
|
||||
|
||||
|
||||
+67
-33
@@ -556,21 +556,6 @@ SOURCE=.\simgear\math\vector.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\math\fastmath.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgmath"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgmath"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\math\SGGeodesy.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
@@ -1184,21 +1169,6 @@ SOURCE=.\simgear\scene\model\animation.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\custtrans.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgmodel"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgmodel"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\location.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
@@ -1244,7 +1214,7 @@ SOURCE=.\simgear\scene\model\modellib.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\personality.cxx
|
||||
SOURCE=.\simgear\scene\model\persparam.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -1289,7 +1259,7 @@ SOURCE=.\simgear\scene\model\placementtrans.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\shadowvolume.cxx
|
||||
SOURCE=.\simgear\scene\model\shadanim.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -1304,7 +1274,7 @@ SOURCE=.\simgear\scene\model\shadowvolume.cxx
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\model\shadanim.cxx
|
||||
SOURCE=.\simgear\scene\model\SGMaterialAnimation.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
@@ -1549,6 +1519,40 @@ SOURCE=.\simgear\scene\tgdb\userdata.cxx
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lib_sgutil"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\util\SGStateAttributeVisitor.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgutil"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgutil"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\scene\util\SGTextureStateAttributeVisitor.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgutil"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgutil"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lib_sgscreen"
|
||||
@@ -1805,6 +1809,36 @@ SOURCE=.\simgear\structure\subsystem_mgr.cxx
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\structure\SGAtomic.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgstructure"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgstructure"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\simgear\structure\SGBinding.cxx
|
||||
|
||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||
|
||||
# PROP Intermediate_Dir "Release\Lib_sgstructure"
|
||||
|
||||
!ELSEIF "$(CFG)" == "SimGear - Win32 Debug"
|
||||
|
||||
# PROP Intermediate_Dir "Debug\Lib_sgstructure"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Lib_sgtiming"
|
||||
|
||||
@@ -47,6 +47,18 @@ Jean-Francois Doue
|
||||
http://www.animats.com/simpleppp/ftp/public_html/topics/developers.html
|
||||
|
||||
|
||||
Melchior Franz
|
||||
METAR parser and fetcher. "material" animation (based on Jim Wilsons's
|
||||
"emission" animation). Debugging and extension of property listener
|
||||
features. Addition of removeChildren.
|
||||
|
||||
|
||||
Mathias Froehlich
|
||||
Reworked and cleaned up large parts of the infrastructure, of math
|
||||
files, animations and rendering in preparation of a transition to
|
||||
the OSG library. Added new handlers for shared and referenced objects.
|
||||
|
||||
|
||||
Bruce Finney <bfinney@gte.net>
|
||||
MSVC5 compatibility.
|
||||
|
||||
@@ -71,6 +83,10 @@ Bruce Jackson of NASA <e.b.jackson@larc.nasa.gov>
|
||||
http://dcb.larc.nasa.gov/www/DCBStaff/ebj/ebj.html
|
||||
|
||||
|
||||
Maik Justus
|
||||
Fixed an old bug in the SGPropertyNode class.
|
||||
|
||||
|
||||
Richard Kaszeta <bofh@me.umn.edu>
|
||||
Contributed screen buffer to ppm screen shot routine.
|
||||
Rich has also helped in the early development of the Flight Gear "altitude
|
||||
@@ -90,6 +106,11 @@ David Megginson <david@megginson.com>
|
||||
SimGear property manager/registry
|
||||
|
||||
|
||||
Tim Moore
|
||||
Ported the (chrome) "shader" animation to OSG, and helped with porting
|
||||
the "material" animation.
|
||||
|
||||
|
||||
Curt Olson http://www.flightgear.org/~curt/
|
||||
Curt is responsible for overall project and source code management.
|
||||
He has his hands in many of the areas.
|
||||
|
||||
+12
-3
@@ -119,6 +119,14 @@ if test "x$with_plib" != "x" ; then
|
||||
EXTRA_DIRS="${EXTRA_DIRS} $with_plib"
|
||||
fi
|
||||
|
||||
# specify the osg location
|
||||
AC_ARG_WITH(osg, [ --with-osg=PREFIX Specify the prefix path to osg])
|
||||
|
||||
if test "x$with_osg" != "x" ; then
|
||||
echo "osg prefix is $with_osg"
|
||||
EXTRA_DIRS="${EXTRA_DIRS} $with_osg"
|
||||
fi
|
||||
|
||||
dnl Determine an extra directories to add to include/lib search paths
|
||||
case "${host}" in
|
||||
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
|
||||
@@ -261,10 +269,10 @@ OPENAL_OK="no"
|
||||
case "${host}" in
|
||||
*-*-cygwin* | *-*-mingw32*)
|
||||
dnl CygWin under Windoze.
|
||||
INCLUDES="$INCLUDES -I/usr/local/include"
|
||||
INCLUDES="$INCLUDES -I/usr/local/include/"
|
||||
LIBS="$LIBS -L/usr/local/lib"
|
||||
AC_SEARCH_LIBS(alGenBuffers, openal32)
|
||||
AC_SEARCH_LIBS(alutInit, [ openal32 ALut ] )
|
||||
AC_SEARCH_LIBS(alGenBuffers, [ openal32 openal ] )
|
||||
AC_SEARCH_LIBS(alutInit, [ openal32 ALut alut ] )
|
||||
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
|
||||
openal_LIBS="$LIBS"
|
||||
OPENAL_OK="$ac_cv_search_alGenBuffers"
|
||||
@@ -430,6 +438,7 @@ AC_CONFIG_FILES([ \
|
||||
simgear/scene/model/Makefile \
|
||||
simgear/scene/sky/Makefile \
|
||||
simgear/scene/tgdb/Makefile \
|
||||
simgear/scene/util/Makefile \
|
||||
simgear/screen/Makefile \
|
||||
simgear/serial/Makefile \
|
||||
simgear/sound/Makefile \
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
Debug
|
||||
Release
|
||||
SimGear.ncb
|
||||
SimGear.suo
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimGear", "SimGear.vcproj", "{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Debug.ActiveCfg = Debug|Win32
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Debug.Build.0 = Debug|Win32
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release.ActiveCfg = Release|Win32
|
||||
{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Executable
+1079
File diff suppressed because it is too large
Load Diff
+171
-43
@@ -41,11 +41,11 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../AL/include;"../../../zlib-1.2.3";"../../../Pre-built.2/include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
@@ -103,11 +103,11 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../AL/include;"../../../zlib-1.2.3";"../../../Pre-built.2/include""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
||||
StringPooling="true"
|
||||
MinimalRebuild="true"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeLibrary="2"
|
||||
FloatingPointModel="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
@@ -215,10 +215,6 @@
|
||||
RelativePath="..\..\simgear\magvar\coremag.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\custtrans.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\data.h"
|
||||
>
|
||||
@@ -247,10 +243,6 @@
|
||||
RelativePath="..\..\simgear\screen\extensions.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\fastmath.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\timing\geocoord.h"
|
||||
>
|
||||
@@ -511,6 +503,26 @@
|
||||
RelativePath="..\..\simgear\math\sg_types.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGAtomic.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGBinding.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGCMath.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGDebugDrawCallback.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGGeoc.hxx"
|
||||
>
|
||||
@@ -531,10 +543,18 @@
|
||||
RelativePath="..\..\simgear\math\SGLimits.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGMath.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGMathFwd.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGMatrix.hxx"
|
||||
>
|
||||
@@ -543,6 +563,18 @@
|
||||
RelativePath="..\..\simgear\math\SGMisc.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGNodeMasks.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGOceanTile.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGQuat.hxx"
|
||||
>
|
||||
@@ -555,18 +587,54 @@
|
||||
RelativePath="..\..\simgear\structure\SGReferenced.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGRotateTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGScaleTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneFeatures.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneUserData.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGSharedPtr.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\misc\sgstream.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\threads\SGThread.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGUpdateVisitor.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGVec3.hxx"
|
||||
>
|
||||
@@ -583,20 +651,6 @@
|
||||
RelativePath="..\..\simgear\scene\model\shadowvolume.hxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\simgear_config.h"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description=""
|
||||
CommandLine=""
|
||||
Outputs=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\sky\sky.hxx"
|
||||
>
|
||||
@@ -761,6 +815,10 @@
|
||||
RelativePath="..\..\simgear\scene\sky\bbcache.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\bitslib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\ephemeris\celestialBody.cxx"
|
||||
>
|
||||
@@ -793,10 +851,6 @@
|
||||
RelativePath="..\..\simgear\magvar\coremag.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\custtrans.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\sky\dome.cxx"
|
||||
>
|
||||
@@ -821,10 +875,6 @@
|
||||
RelativePath="..\..\simgear\screen\extensions.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\fastmath.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\gc.c"
|
||||
>
|
||||
@@ -858,11 +908,11 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
|
||||
RelativePath="..\..\simgear\nasal\iolib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\leaf.cxx"
|
||||
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@@ -970,7 +1020,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\personality.cxx"
|
||||
RelativePath="..\..\simgear\scene\model\persparam.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@@ -1057,18 +1107,70 @@
|
||||
RelativePath="..\..\simgear\timing\sg_time.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\structure\SGBinding.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\math\SGGeodesy.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGOceanTile.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGRotateTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGScaleTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneFeatures.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGSceneUserData.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\misc\sgstream.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\threads\SGThread.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\shadanim.cxx"
|
||||
>
|
||||
@@ -1077,10 +1179,6 @@
|
||||
RelativePath="..\..\simgear\screen\shader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\model\shadowvolume.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\scene\sky\sky.cxx"
|
||||
>
|
||||
@@ -1137,6 +1235,10 @@
|
||||
RelativePath="..\..\simgear\nasal\thread-win32.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\threadlib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\timing\timestamp.cxx"
|
||||
>
|
||||
@@ -1157,6 +1259,10 @@
|
||||
RelativePath="..\..\simgear\scene\tgdb\userdata.cxx"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\utf8lib.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\simgear\nasal\vector.c"
|
||||
>
|
||||
@@ -1214,6 +1320,28 @@
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\..\simgear\simgear_config.h-msvc71"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" "$(InputDir)\$(InputName).h"
"
|
||||
Outputs=""${InputDir}\$(InputName).h""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" "$(InputDir)\$(InputName).h"
"
|
||||
Outputs="${InputDir}\$(InputName).h"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ endif
|
||||
# METAR_DIRS =
|
||||
METAR_DIRS = environment
|
||||
|
||||
EXTRA_DIST = simgear_config.h.vc5 version.h.in
|
||||
EXTRA_DIST = simgear_config.h.vc5 simgear_config.h-msvc71 version.h.in
|
||||
|
||||
include_HEADERS = \
|
||||
compiler.h constants.h sg_inlines.h sg_traits.hxx version.h
|
||||
@@ -34,4 +34,4 @@ SUBDIRS = \
|
||||
$(SGTHREAD_DIR) \
|
||||
timing
|
||||
|
||||
DIST_SUBDIRS = $(SUBDIRS) compatibility threads
|
||||
DIST_SUBDIRS = $(SUBDIRS) compatibility
|
||||
|
||||
@@ -44,6 +44,9 @@ SGBucket::SGBucket(const double dlon, const double dlat) {
|
||||
set_bucket(dlon, dlat);
|
||||
}
|
||||
|
||||
SGBucket::SGBucket(const SGGeod& geod) {
|
||||
set_bucket(geod);
|
||||
}
|
||||
|
||||
// create an impossible bucket if false
|
||||
SGBucket::SGBucket(const bool is_good) {
|
||||
@@ -73,11 +76,6 @@ SGBucket::SGBucket(const long int bindex) {
|
||||
}
|
||||
|
||||
|
||||
// default destructor
|
||||
SGBucket::~SGBucket() {
|
||||
}
|
||||
|
||||
|
||||
// Set the bucket params for the specified lat and lon
|
||||
void SGBucket::set_bucket( double *lonlat ) {
|
||||
set_bucket( lonlat[0], lonlat[1] );
|
||||
@@ -135,6 +133,11 @@ void SGBucket::set_bucket( double dlon, double dlat ) {
|
||||
}
|
||||
|
||||
|
||||
void SGBucket::set_bucket(const SGGeod& geod)
|
||||
{
|
||||
set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
|
||||
}
|
||||
|
||||
// Build the path name for this bucket
|
||||
string SGBucket::gen_base_path() const {
|
||||
// long int index;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
# include <cmath>
|
||||
@@ -133,6 +134,13 @@ public:
|
||||
*/
|
||||
SGBucket(const double dlon, const double dlat);
|
||||
|
||||
/**
|
||||
* Construct a bucket given a specific location.
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
SGBucket(const SGGeod& geod);
|
||||
|
||||
/** Construct a bucket.
|
||||
* @param is_good if false, create an invalid bucket. This is
|
||||
* useful * if you are comparing cur_bucket to last_bucket and
|
||||
@@ -146,11 +154,6 @@ public:
|
||||
*/
|
||||
SGBucket(const long int bindex);
|
||||
|
||||
/**
|
||||
* Default destructor.
|
||||
*/
|
||||
~SGBucket();
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param dlon longitude specified in degrees
|
||||
@@ -165,6 +168,13 @@ public:
|
||||
*/
|
||||
void set_bucket( double *lonlat );
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
void set_bucket(const SGGeod& geod);
|
||||
|
||||
/**
|
||||
* Create an impossible bucket.
|
||||
* This is useful if you are comparing cur_bucket to last_bucket
|
||||
@@ -252,7 +262,24 @@ public:
|
||||
* @return the height of the tile in meters.
|
||||
*/
|
||||
double get_height_m() const;
|
||||
|
||||
|
||||
/**
|
||||
* @return the center of the bucket in geodetic coordinates.
|
||||
*/
|
||||
SGGeod get_center() const
|
||||
{ return SGGeod::fromDeg(get_center_lon(), get_center_lat()); }
|
||||
|
||||
/**
|
||||
* @return the center of the bucket in geodetic coordinates.
|
||||
*/
|
||||
SGGeod get_corner(unsigned num) const
|
||||
{
|
||||
double lonFac = ((num + 1) & 2) ? 0.5 : -0.5;
|
||||
double latFac = ((num ) & 2) ? 0.5 : -0.5;
|
||||
return SGGeod::fromDeg(get_center_lon() + lonFac*get_width(),
|
||||
get_center_lat() + latFac*get_height());
|
||||
}
|
||||
|
||||
// Informational methods.
|
||||
|
||||
/**
|
||||
|
||||
@@ -230,6 +230,7 @@
|
||||
|
||||
# define isnan _isnan
|
||||
# define snprintf _snprintf
|
||||
# define copysign _copysign
|
||||
|
||||
# pragma warning(disable: 4786) // identifier was truncated to '255' characters
|
||||
# pragma warning(disable: 4244) // conversion from double to float
|
||||
|
||||
@@ -128,6 +128,12 @@
|
||||
/** Knots to Miles per second */
|
||||
#define SG_KT_TO_MPS 0.5144444444444444444
|
||||
|
||||
/** Feet per second to Knots */
|
||||
#define SG_FPS_TO_KT 0.5924838012958962841
|
||||
|
||||
/** Knots to Feet per second */
|
||||
#define SG_KT_TO_FPS 1.6878098571011956874
|
||||
|
||||
/** Miles per second to Miles per hour */
|
||||
#define SG_MPS_TO_MPH 2.2369362920544020312
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
logstream *global_logstream = NULL;
|
||||
|
||||
bool logbuf::logging_enabled = true;
|
||||
#ifdef _MSC_VER
|
||||
bool logbuf::has_console = true;
|
||||
#endif
|
||||
sgDebugClass logbuf::logClass = SG_NONE;
|
||||
sgDebugPriority logbuf::logPriority = SG_INFO;
|
||||
streambuf* logbuf::sbuf = NULL;
|
||||
|
||||
@@ -139,6 +139,10 @@ public:
|
||||
*/
|
||||
void set_sb( streambuf* sb );
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static void has_no_console() { has_console = false; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
/** sync/flush */
|
||||
@@ -154,6 +158,9 @@ private:
|
||||
static streambuf* sbuf;
|
||||
|
||||
static bool logging_enabled;
|
||||
#ifdef _MSC_VER
|
||||
static bool has_console;
|
||||
#endif
|
||||
static sgDebugClass logClass;
|
||||
static sgDebugPriority logPriority;
|
||||
|
||||
@@ -184,7 +191,6 @@ inline logbuf::int_type
|
||||
logbuf::overflow( int c )
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
static bool has_console = false;
|
||||
if ( logging_enabled ) {
|
||||
if ( !has_console ) {
|
||||
AllocConsole();
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
* @file metar.cxx
|
||||
* Interface for encoded Meteorological Aerodrome Reports (METAR).
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
@@ -744,6 +747,14 @@ bool SGMetar::scanSkyCondition()
|
||||
int i;
|
||||
SGMetarCloud cl;
|
||||
|
||||
if (!strncmp(m, "//////", 6)) {
|
||||
m += 6;
|
||||
if (!scanBoundary(&m))
|
||||
return false;
|
||||
_m = m;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strncmp(m, "CLR", i = 3) // clear
|
||||
|| !strncmp(m, "SKC", i = 3) // sky clear
|
||||
|| !strncmp(m, "NSC", i = 3) // no significant clouds
|
||||
@@ -833,7 +844,7 @@ bool SGMetar::scanTemperature()
|
||||
return false;
|
||||
if (!scanBoundary(&m)) {
|
||||
if (!strncmp(m, "XX", 2)) // not spec compliant!
|
||||
m += 2, sign = 0;
|
||||
m += 2, sign = 0, dew = temp;
|
||||
else {
|
||||
sign = 1;
|
||||
if (*m == 'M')
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
// Minor changes/additions by Vivian Meazza Apr- May 2007
|
||||
//
|
||||
// Ported to OSG by Tim Moore Jun 2007
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
@@ -23,7 +26,6 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
@@ -190,6 +192,8 @@ SGEnviro::SGEnviro() :
|
||||
}
|
||||
|
||||
SGEnviro::~SGEnviro(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
list_of_lightning::iterator iLightning;
|
||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||
delete (*iLightning);
|
||||
@@ -198,6 +202,8 @@ SGEnviro::~SGEnviro(void) {
|
||||
}
|
||||
|
||||
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
view_in_cloud = false;
|
||||
// ask the impostor cache to do some cleanup
|
||||
if(SGNewCloud::cldCache)
|
||||
@@ -320,13 +326,15 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
|
||||
}
|
||||
|
||||
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
sgCopyVec4( fog_color, adj_fog_color );
|
||||
if( false ) {
|
||||
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
||||
}
|
||||
}
|
||||
|
||||
void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) {
|
||||
void SGEnviro::callback_cloud(float bearing, float alt, float radius, int family, float dist, int cloudId) {
|
||||
// send data to wx radar
|
||||
// compute turbulence
|
||||
// draw precipitation
|
||||
@@ -398,9 +406,10 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
|
||||
LWC = 0.29*2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
// add to the list for the wxRadar instrument
|
||||
if( LWC > 0.0 )
|
||||
radarEcho.push_back( SGWxRadarEcho ( heading, alt, radius, dist, LWC, false, cloudId ) );
|
||||
radarEcho.push_back( SGWxRadarEcho ( bearing, alt, radius, dist, 0.0 , LWC, false, cloudId, false ) );
|
||||
|
||||
// NB:data valid only from cockpit view
|
||||
|
||||
@@ -413,7 +422,7 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
|
||||
orig.setlon(last_lon * SG_DEGREES_TO_RADIANS );
|
||||
orig.setelev(0.0);
|
||||
dist = sgSqrt(dist);
|
||||
dest = calc_gc_lon_lat(orig, heading, dist);
|
||||
dest = calc_gc_lon_lat(orig, bearing, dist);
|
||||
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
|
||||
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
||||
addLightning( lon, lat, alt );
|
||||
@@ -441,6 +450,8 @@ list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
|
||||
|
||||
// precipitation rendering code
|
||||
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
sgVec3 light;
|
||||
sgAddVec3( light, fog_color, min_light );
|
||||
float da = SG_PI * 2.0f / (float) slices;
|
||||
@@ -489,6 +500,8 @@ void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down,
|
||||
}
|
||||
|
||||
void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
|
||||
#if 0
|
||||
static int debug_period = 0;
|
||||
@@ -558,6 +571,8 @@ void SGEnviro::set_soundMgr(SGSoundMgr *mgr) {
|
||||
}
|
||||
|
||||
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
if( precipitation_enable_state && rain_norm > 0.0)
|
||||
if( precipitation_max_alt >= last_alt )
|
||||
drawRain(pitch, roll, heading, hspeed, rain_norm);
|
||||
@@ -580,6 +595,8 @@ SGLightning::~SGLightning() {
|
||||
|
||||
// lightning rendering code
|
||||
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
|
||||
sgVec3 dir, newdir;
|
||||
int nseg = 0;
|
||||
@@ -627,6 +644,8 @@ void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy
|
||||
}
|
||||
|
||||
void SGLightning::lt_build(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
Point3D top;
|
||||
nb_tree = 0;
|
||||
top[PX] = 0 ;
|
||||
@@ -652,6 +671,8 @@ void SGLightning::lt_build(void) {
|
||||
|
||||
|
||||
void SGLightning::lt_Render(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
float flash = 0.5;
|
||||
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
||||
flash = sg_random() * 0.75f + 0.25f;
|
||||
@@ -676,10 +697,12 @@ void SGLightning::lt_Render(void) {
|
||||
glDisable( GL_FOG );
|
||||
glPushMatrix();
|
||||
sgMat4 modelview, tmp;
|
||||
ssgGetModelviewMatrix( modelview );
|
||||
// OSGFIXME
|
||||
// ssgGetModelviewMatrix( modelview );
|
||||
sgCopyMat4( tmp, sgEnviro.transform );
|
||||
sgPostMultMat4( tmp, modelview );
|
||||
ssgLoadModelviewMatrix( tmp );
|
||||
// OSGFIXME
|
||||
// ssgLoadModelviewMatrix( tmp );
|
||||
|
||||
Point3D start( sgEnviro.last_lon*SG_DEGREES_TO_RADIANS, sgEnviro.last_lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
Point3D dest( lon*SG_DEGREES_TO_RADIANS, lat*SG_DEGREES_TO_RADIANS, 0.0 );
|
||||
@@ -691,7 +714,7 @@ void SGLightning::lt_Render(void) {
|
||||
|
||||
glTranslatef( ax, ay, -sgEnviro.last_alt );
|
||||
|
||||
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, age, true, 0 ) );
|
||||
sgEnviro.radarEcho.push_back( SGWxRadarEcho ( course, 0.0, 0.0, dist, 0.0, age, true, 0, false ) );
|
||||
|
||||
for( int n = 0 ; n < nb_tree ; n++ ) {
|
||||
if( lt_tree[n].prev < 0 )
|
||||
@@ -737,6 +760,8 @@ void SGLightning::lt_Render(void) {
|
||||
}
|
||||
|
||||
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
if( lightnings.size() > 10)
|
||||
return;
|
||||
SGLightning *lt= new SGLightning(lon, lat, alt);
|
||||
@@ -744,6 +769,8 @@ void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||
}
|
||||
|
||||
void SGEnviro::drawLightning(void) {
|
||||
// OSGFIXME
|
||||
return;
|
||||
list_of_lightning::iterator iLightning;
|
||||
// play 'thunder' for lightning
|
||||
if( snd_active )
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Visual environment helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started April 2005.
|
||||
// Minor changes/additions by Vivian Meazza Apr- May 2007
|
||||
//
|
||||
// Ported to OSG by Tim Moore Jun 2007
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
@@ -22,6 +25,8 @@
|
||||
#ifndef _VISUAL_ENVIRO_HXX
|
||||
#define _VISUAL_ENVIRO_HXX
|
||||
|
||||
#include <plib/sg.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include STL_STRING
|
||||
#include <vector>
|
||||
@@ -38,23 +43,32 @@ class SGSoundMgr;
|
||||
*/
|
||||
class SGWxRadarEcho {
|
||||
public:
|
||||
SGWxRadarEcho(float _heading, float _alt, float _radius, float _dist, double _LWC, bool _lightning, int _cloudId) :
|
||||
SGWxRadarEcho(float _bearing, float _alt, float _radius, float _dist, float _heading,
|
||||
double _LWC, bool _lightning, int _cloudId, bool _aircraft) :
|
||||
bearing (_bearing),
|
||||
heading( _heading ),
|
||||
alt ( _alt ),
|
||||
radius ( _radius ),
|
||||
dist ( _dist ),
|
||||
LWC ( _LWC ),
|
||||
lightning ( _lightning ),
|
||||
aircraft ( _aircraft ),
|
||||
cloudId ( _cloudId )
|
||||
{}
|
||||
|
||||
/** the heading in radian is versus north */
|
||||
float heading;
|
||||
/** the heading and bearing in radian are versus north */
|
||||
float bearing, heading;
|
||||
float alt, radius, dist;
|
||||
|
||||
/** reflectivity converted to liquid water content. */
|
||||
double LWC;
|
||||
|
||||
/** if true then this data is for a lightning else it is for water echo. */
|
||||
bool lightning;
|
||||
|
||||
/** if true then this data is for an aircraft */
|
||||
bool aircraft;
|
||||
|
||||
/** Unique identifier of cloud */
|
||||
int cloudId;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
|
||||
// Constructor
|
||||
SGEphemeris::SGEphemeris( const string &path ) {
|
||||
SGEphemeris::SGEphemeris( const std::string &path ) {
|
||||
our_sun = new Star;
|
||||
moon = new MoonPos;
|
||||
mercury = new Mercury;
|
||||
@@ -42,9 +42,8 @@ SGEphemeris::SGEphemeris( const string &path ) {
|
||||
uranus = new Uranus;
|
||||
neptune = new Neptune;
|
||||
nplanets = 7;
|
||||
for ( int i = 0; i < nplanets; ++i ) {
|
||||
sgdSetVec3( planets[i], 0.0, 0.0, 0.0 );
|
||||
}
|
||||
for ( int i = 0; i < nplanets; ++i )
|
||||
planets[i] = SGVec3d::zeros();
|
||||
stars = new SGStarData( SGPath(path) );
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
#ifndef _EPHEMERIS_HXX
|
||||
#define _EPHEMERIS_HXX
|
||||
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <string>
|
||||
|
||||
#include <simgear/ephemeris/star.hxx>
|
||||
#include <simgear/ephemeris/moonpos.hxx>
|
||||
@@ -43,6 +42,9 @@
|
||||
#include <simgear/ephemeris/neptune.hxx>
|
||||
#include <simgear/ephemeris/stardata.hxx>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
/** Ephemeris class
|
||||
*
|
||||
@@ -83,7 +85,7 @@ class SGEphemeris {
|
||||
// planets[i][1] = Declination
|
||||
// planets[i][2] = Magnitude
|
||||
int nplanets;
|
||||
sgdVec3 planets[7];
|
||||
SGVec3d planets[7];
|
||||
|
||||
SGStarData *stars;
|
||||
|
||||
@@ -95,7 +97,7 @@ public:
|
||||
* calling the constructor you need to provide a path pointing to
|
||||
* your star database file.
|
||||
* @param path path to your star database */
|
||||
SGEphemeris( const string &path );
|
||||
SGEphemeris( const std::string &path );
|
||||
|
||||
/** Destructor */
|
||||
~SGEphemeris( void );
|
||||
@@ -155,7 +157,7 @@ public:
|
||||
* the second is the declination, and the third is the magnitude.
|
||||
* @return planets array
|
||||
*/
|
||||
inline sgdVec3 *getPlanets() { return planets; }
|
||||
inline SGVec3d *getPlanets() { return planets; }
|
||||
|
||||
/** @return the numbers of defined stars. */
|
||||
inline int getNumStars() const { return stars->getNumStars(); }
|
||||
@@ -167,7 +169,7 @@ public:
|
||||
* third is the magnitude.
|
||||
* @returns star array
|
||||
*/
|
||||
inline sgdVec3 *getStars() { return stars->getStars(); }
|
||||
inline SGVec3d *getStars() { return stars->getStars(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include "stardata.hxx"
|
||||
@@ -34,16 +35,9 @@
|
||||
#endif
|
||||
|
||||
// Constructor
|
||||
SGStarData::SGStarData() :
|
||||
nstars(0)
|
||||
SGStarData::SGStarData( const SGPath& path )
|
||||
{
|
||||
}
|
||||
|
||||
SGStarData::SGStarData( SGPath path ) :
|
||||
nstars(0)
|
||||
{
|
||||
data_path = SGPath( path );
|
||||
load();
|
||||
load(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,31 +46,28 @@ SGStarData::~SGStarData() {
|
||||
}
|
||||
|
||||
|
||||
bool SGStarData::load() {
|
||||
bool SGStarData::load( const SGPath& path ) {
|
||||
|
||||
// -dw- avoid local data > 32k error by dynamic allocation of the
|
||||
// array, problem for some compilers
|
||||
stars = new sgdVec3[SG_MAX_STARS];
|
||||
_stars.clear();
|
||||
|
||||
// build the full path name to the stars data base file
|
||||
data_path.append( "stars" );
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << data_path.str() );
|
||||
// build the full path name to the stars data base file
|
||||
SGPath tmp = path;
|
||||
tmp.append( "stars" );
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << tmp.str() );
|
||||
|
||||
sg_gzifstream in( data_path.str() );
|
||||
sg_gzifstream in( tmp.str() );
|
||||
if ( ! in.is_open() ) {
|
||||
SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: "
|
||||
<< data_path.str() );
|
||||
exit(-1);
|
||||
<< tmp.str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
double ra, dec, mag;
|
||||
char c;
|
||||
string name;
|
||||
|
||||
nstars = 0;
|
||||
|
||||
// read in each line of the file
|
||||
while ( ! in.eof() && nstars < SG_MAX_STARS ) {
|
||||
while ( ! in.eof() ) {
|
||||
in >> skipcomment;
|
||||
|
||||
getline( in, name, ',' );
|
||||
@@ -116,13 +107,10 @@ bool SGStarData::load() {
|
||||
in >> mag;
|
||||
|
||||
// cout << " star data = " << ra << " " << dec << " " << mag << endl;
|
||||
|
||||
sgdSetVec3( stars[nstars], ra, dec, mag );
|
||||
|
||||
++nstars;
|
||||
_stars.push_back(SGVec3d(ra, dec, mag));
|
||||
}
|
||||
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << nstars << " stars" );
|
||||
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << _stars.size() << " stars" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,37 +24,28 @@
|
||||
#ifndef _SG_STARDATA_HXX
|
||||
#define _SG_STARDATA_HXX
|
||||
|
||||
#include <vector>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <plib/sg.h>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
#define SG_MAX_STARS 850
|
||||
|
||||
class SGPath;
|
||||
|
||||
class SGStarData {
|
||||
|
||||
int nstars;
|
||||
sgdVec3 *stars;
|
||||
|
||||
SGPath data_path;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
SGStarData();
|
||||
SGStarData( SGPath path );
|
||||
SGStarData( const SGPath& path );
|
||||
|
||||
// Destructor
|
||||
~SGStarData();
|
||||
|
||||
// load the stars database
|
||||
bool load();
|
||||
bool load( const SGPath& path );
|
||||
|
||||
// stars
|
||||
inline int getNumStars() const { return nstars; }
|
||||
inline sgdVec3 *getStars() { return stars; }
|
||||
inline int getNumStars() const { return _stars.size(); }
|
||||
inline SGVec3d *getStars() { return &(_stars[0]); }
|
||||
|
||||
private:
|
||||
std::vector<SGVec3d> _stars;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ int main( int argc, char **argv ) {
|
||||
obj.get_gbs_radius());
|
||||
cout << endl;
|
||||
|
||||
point_list nodes = obj.get_wgs84_nodes();
|
||||
std::vector<SGVec3d> nodes = obj.get_wgs84_nodes();
|
||||
cout << "# vertex list" << endl;
|
||||
for ( i = 0; i < (int)nodes.size(); ++i ) {
|
||||
printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() );
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
point_list normals = obj.get_normals();
|
||||
std::vector<SGVec3f> normals = obj.get_normals();
|
||||
cout << "# vertex normal list" << endl;
|
||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||
printf("vn %.5f %.5f %.5f\n",
|
||||
@@ -52,7 +52,7 @@ int main( int argc, char **argv ) {
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
point_list texcoords = obj.get_texcoords();
|
||||
std::vector<SGVec2f> texcoords = obj.get_texcoords();
|
||||
cout << "# texture coordinate list" << endl;
|
||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||
printf("vt %.5f %.5f\n",
|
||||
|
||||
+30
-45
@@ -174,7 +174,7 @@ static void read_object( gzFile fp,
|
||||
int idx_size;
|
||||
bool do_vertices, do_normals, do_colors, do_texcoords;
|
||||
int j, k, idx;
|
||||
static sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
char material[256];
|
||||
|
||||
// default values
|
||||
@@ -280,13 +280,13 @@ static void read_object( gzFile fp,
|
||||
|
||||
// read a binary file and populate the provided structures.
|
||||
bool SGBinObject::read_bin( const string& file ) {
|
||||
Point3D p;
|
||||
SGVec3d p;
|
||||
int i, j, k;
|
||||
unsigned int nbytes;
|
||||
static sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||
|
||||
// zero out structures
|
||||
gbs_center = Point3D( 0 );
|
||||
gbs_center = SGVec3d(0, 0, 0);
|
||||
gbs_radius = 0.0;
|
||||
|
||||
wgs84_nodes.clear();
|
||||
@@ -322,7 +322,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
string filegz = file + ".gz";
|
||||
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
|
||||
SG_LOG( SG_EVENT, SG_ALERT,
|
||||
"ERROR: opening " << file << " or " << filegz << "for reading!");
|
||||
"ERROR: opening " << file << " or " << filegz << " for reading!");
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -407,7 +407,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint64_t *)&(dptr[1]) );
|
||||
sgEndianSwap( (uint64_t *)&(dptr[2]) );
|
||||
}
|
||||
gbs_center = Point3D( dptr[0], dptr[1], dptr[2] );
|
||||
gbs_center = SGVec3d( dptr[0], dptr[1], dptr[2] );
|
||||
// cout << "Center = " << gbs_center << endl;
|
||||
ptr += sizeof(double) * 3;
|
||||
|
||||
@@ -447,7 +447,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||
}
|
||||
wgs84_nodes.push_back( Point3D(fptr[0], fptr[1], fptr[2]) );
|
||||
wgs84_nodes.push_back( SGVec3d(fptr[0], fptr[1], fptr[2]) );
|
||||
fptr += 3;
|
||||
}
|
||||
}
|
||||
@@ -481,7 +481,8 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[3]) );
|
||||
}
|
||||
colors.push_back( Point3D( fptr[0], fptr[1], fptr[2] ) );
|
||||
SGVec4f color( fptr[0], fptr[1], fptr[2], fptr[3] );
|
||||
colors.push_back( color );
|
||||
fptr += 4;
|
||||
}
|
||||
}
|
||||
@@ -508,14 +509,11 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
int count = nbytes / 3;
|
||||
normals.reserve( count );
|
||||
for ( k = 0; k < count; ++k ) {
|
||||
sgdVec3 normal;
|
||||
sgdSetVec3( normal,
|
||||
(ptr[0]) / 127.5 - 1.0,
|
||||
(ptr[1]) / 127.5 - 1.0,
|
||||
(ptr[2]) / 127.5 - 1.0 );
|
||||
sgdNormalizeVec3( normal );
|
||||
SGVec3f normal((ptr[0]) / 127.5 - 1.0,
|
||||
(ptr[1]) / 127.5 - 1.0,
|
||||
(ptr[2]) / 127.5 - 1.0);
|
||||
|
||||
normals.push_back(Point3D(normal[0], normal[1], normal[2]));
|
||||
normals.push_back(normalize(normal));
|
||||
ptr += 3;
|
||||
}
|
||||
}
|
||||
@@ -547,7 +545,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||
}
|
||||
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) );
|
||||
texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) );
|
||||
fptr += 2;
|
||||
}
|
||||
}
|
||||
@@ -612,10 +610,6 @@ bool SGBinObject::read_bin( const string& file ) {
|
||||
bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
const SGBucket& b )
|
||||
{
|
||||
Point3D p;
|
||||
sgVec2 t;
|
||||
sgVec3 pt;
|
||||
sgVec4 color;
|
||||
int i, j;
|
||||
unsigned char idx_mask;
|
||||
int idx_size;
|
||||
@@ -738,9 +732,8 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteShort( fp, 1 ); // nelements
|
||||
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
|
||||
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
||||
p = wgs84_nodes[i] - gbs_center;
|
||||
sgSetVec3( pt, p.x(), p.y(), p.z() );
|
||||
sgWriteVec3( fp, pt );
|
||||
SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center);
|
||||
sgWriteVec3( fp, p.data() );
|
||||
}
|
||||
|
||||
// dump vertex color list
|
||||
@@ -749,12 +742,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteShort( fp, 1 ); // nelements
|
||||
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
|
||||
for ( i = 0; i < (int)colors.size(); ++i ) {
|
||||
p = colors[i];
|
||||
// Right now we have a place holder for color alpha but we
|
||||
// need to update the interface so the calling program can
|
||||
// provide the info.
|
||||
sgSetVec4( color, p.x(), p.y(), p.z(), 1.0 );
|
||||
sgWriteVec4( fp, color );
|
||||
sgWriteVec4( fp, colors[i].data() );
|
||||
}
|
||||
|
||||
// dump vertex normal list
|
||||
@@ -764,7 +752,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
|
||||
char normal[3];
|
||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||
p = normals[i];
|
||||
SGVec3f p = normals[i];
|
||||
normal[0] = (unsigned char)((p.x() + 1.0) * 127.5);
|
||||
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
|
||||
normal[2] = (unsigned char)((p.z() + 1.0) * 127.5);
|
||||
@@ -777,9 +765,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
sgWriteShort( fp, 1 ); // nelements
|
||||
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
|
||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||
p = texcoords[i];
|
||||
sgSetVec2( t, p.x(), p.y() );
|
||||
sgWriteVec2( fp, t );
|
||||
sgWriteVec2( fp, texcoords[i].data() );
|
||||
}
|
||||
|
||||
// dump point groups if they exist
|
||||
@@ -1042,7 +1028,6 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
||||
bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
const SGBucket& b )
|
||||
{
|
||||
Point3D p;
|
||||
int i, j;
|
||||
|
||||
SGPath file = base + "/" + b.gen_base_path() + "/" + name;
|
||||
@@ -1084,7 +1069,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// dump vertex list
|
||||
fprintf(fp, "# vertex list\n");
|
||||
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
||||
p = wgs84_nodes[i] - gbs_center;
|
||||
SGVec3d p = wgs84_nodes[i] - gbs_center;
|
||||
|
||||
fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
|
||||
}
|
||||
@@ -1092,7 +1077,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
|
||||
fprintf(fp, "# vertex normal list\n");
|
||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||
p = normals[i];
|
||||
SGVec3f p = normals[i];
|
||||
fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
@@ -1100,7 +1085,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// dump texture coordinates
|
||||
fprintf(fp, "# texture coordinate list\n");
|
||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||
p = texcoords[i];
|
||||
SGVec2f p = texcoords[i];
|
||||
fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() );
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
@@ -1126,13 +1111,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// make a list of points for the group
|
||||
point_list group_nodes;
|
||||
group_nodes.clear();
|
||||
Point3D bs_center;
|
||||
SGVec3d bs_center;
|
||||
double bs_radius = 0;
|
||||
for ( i = start; i < end; ++i ) {
|
||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] );
|
||||
bs_center = sgCalcCenter( group_nodes );
|
||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
||||
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ tris_v[i][j] ]) );
|
||||
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
|
||||
bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,13 +1162,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||
// make a list of points for the group
|
||||
point_list group_nodes;
|
||||
group_nodes.clear();
|
||||
Point3D bs_center;
|
||||
SGVec3d bs_center;
|
||||
double bs_radius = 0;
|
||||
for ( i = start; i < end; ++i ) {
|
||||
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
||||
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] );
|
||||
bs_center = sgCalcCenter( group_nodes );
|
||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
||||
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ strips_v[i][j] ]) );
|
||||
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
|
||||
bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+43
-15
@@ -89,13 +89,13 @@ typedef group_list::const_iterator const_group_list_iterator;
|
||||
class SGBinObject {
|
||||
unsigned short version;
|
||||
|
||||
Point3D gbs_center;
|
||||
SGVec3d gbs_center;
|
||||
float gbs_radius;
|
||||
|
||||
point_list wgs84_nodes; // vertex list
|
||||
point_list colors; // color list
|
||||
point_list normals; // normal list
|
||||
point_list texcoords; // texture coordinate list
|
||||
std::vector<SGVec3d> wgs84_nodes; // vertex list
|
||||
std::vector<SGVec4f> colors; // color list
|
||||
std::vector<SGVec3f> normals; // normal list
|
||||
std::vector<SGVec2f> texcoords; // texture coordinate list
|
||||
|
||||
group_list pts_v; // points vertex index
|
||||
group_list pts_n; // points normal index
|
||||
@@ -125,23 +125,51 @@ public:
|
||||
|
||||
inline unsigned short get_version() const { return version; }
|
||||
|
||||
inline const Point3D& get_gbs_center() const { return gbs_center; }
|
||||
inline void set_gbs_center( const Point3D& p ) { gbs_center = p; }
|
||||
inline Point3D get_gbs_center() const { return Point3D::fromSGVec3(gbs_center); }
|
||||
inline void set_gbs_center( const Point3D& p ) { gbs_center = p.toSGVec3d(); }
|
||||
inline const SGVec3d& get_gbs_center2() const { return gbs_center; }
|
||||
inline void set_gbs_center( const SGVec3d& p ) { gbs_center = p; }
|
||||
|
||||
inline float get_gbs_radius() const { return gbs_radius; }
|
||||
inline void set_gbs_radius( float r ) { gbs_radius = r; }
|
||||
|
||||
inline const point_list& get_wgs84_nodes() const { return wgs84_nodes; }
|
||||
inline void set_wgs84_nodes( const point_list& n ) { wgs84_nodes = n; }
|
||||
inline const std::vector<SGVec3d>& get_wgs84_nodes() const
|
||||
{ return wgs84_nodes; }
|
||||
inline void set_wgs84_nodes( const std::vector<SGVec3d>& n )
|
||||
{ wgs84_nodes = n; }
|
||||
inline void set_wgs84_nodes( const point_list& n )
|
||||
{
|
||||
wgs84_nodes.resize(n.size());
|
||||
for (unsigned i = 0; i < wgs84_nodes.size(); ++i)
|
||||
wgs84_nodes[i] = n[i].toSGVec3d();
|
||||
}
|
||||
|
||||
inline const point_list& get_colors() const { return colors; }
|
||||
inline void set_colors( const point_list& c ) { colors = c; }
|
||||
inline const std::vector<SGVec4f>& get_colors() const { return colors; }
|
||||
inline void set_colors( const std::vector<SGVec4f>& c ) { colors = c; }
|
||||
inline void set_colors( const point_list& c )
|
||||
{
|
||||
colors.resize(c.size());
|
||||
for (unsigned i = 0; i < colors.size(); ++i)
|
||||
colors[i] = SGVec4f(c[i].toSGVec3f(), 1);
|
||||
}
|
||||
|
||||
inline const point_list& get_normals() const { return normals; }
|
||||
inline void set_normals( const point_list& n ) { normals = n; }
|
||||
inline const std::vector<SGVec3f>& get_normals() const { return normals; }
|
||||
inline void set_normals( const std::vector<SGVec3f>& n ) { normals = n; }
|
||||
inline void set_normals( const point_list& n )
|
||||
{
|
||||
normals.resize(n.size());
|
||||
for (unsigned i = 0; i < normals.size(); ++i)
|
||||
normals[i] = n[i].toSGVec3f();
|
||||
}
|
||||
|
||||
inline const point_list& get_texcoords() const { return texcoords; }
|
||||
inline void set_texcoords( const point_list& t ) { texcoords = t; }
|
||||
inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
|
||||
inline void set_texcoords( const std::vector<SGVec2f>& t ) { texcoords = t; }
|
||||
inline void set_texcoords( const point_list& t )
|
||||
{
|
||||
texcoords.resize(t.size());
|
||||
for (unsigned i = 0; i < texcoords.size(); ++i)
|
||||
texcoords[i] = t[i].toSGVec2f();
|
||||
}
|
||||
|
||||
inline const group_list& get_pts_v() const { return pts_v; }
|
||||
inline void set_pts_v( const group_list& g ) { pts_v = g; }
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
+73
-61
@@ -23,6 +23,19 @@
|
||||
//
|
||||
// Put in some bullet-proofing to handle magnetic and geographic poles.
|
||||
// 3/28/2000 EAW
|
||||
//
|
||||
// Updated coefficient arrays to use the current WMM2005 model,
|
||||
// (valid between 2005.0 and 2010.0)
|
||||
// Also removed unused variables and corrected earth radii constants
|
||||
// to the values for WGS84 and WMM2005.
|
||||
// Reference:
|
||||
// McLean, S., S. Macmillan, S. Maus, V. Lesur, A.
|
||||
// Thomson, and D. Dater, December 2004, The
|
||||
// US/UK World Magnetic Model for 2005-2010,
|
||||
// NOAA Technical Report NESDIS/NGDC-1.
|
||||
//
|
||||
// 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
|
||||
//
|
||||
|
||||
// The routine uses a spherical harmonic expansion of the magnetic
|
||||
// potential up to twelfth order, together with its time variation, as
|
||||
@@ -75,74 +88,72 @@
|
||||
|
||||
|
||||
static const double pi = 3.14159265358979;
|
||||
static const double a = 6378.16; /* major radius (km) IAU66 ellipsoid */
|
||||
static const double f = 1.0 / 298.25; /* inverse flattening IAU66 ellipsoid */
|
||||
static const double b = 6378.16 * (1.0 -1.0 / 298.25 );
|
||||
/* minor radius b=a*(1-f) */
|
||||
static const double r_0 = 6371.2; /* "mean radius" for spherical harmonic expansion */
|
||||
static const double a = 6378.137; /* semi-major axis (equatorial radius) of WGS84 ellipsoid */
|
||||
static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
|
||||
static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
|
||||
|
||||
static double gnm_wmm2000[13][13] =
|
||||
static double gnm_wmm2005[13][13] =
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-29616.0, -1722.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2266.7, 3070.2, 1677.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1322.4, -2291.5, 1255.9, 724.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{932.1, 786.3, 250.6, -401.5, 106.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-211.9, 351.6, 220.8, -134.5, -168.8, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{73.8, 68.2, 74.1, -163.5, -3.8, 17.1, -85.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{77.4, -73.9, 2.2, 35.7, 7.3, 5.2, 8.4, -1.5, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{23.3, 7.3, -8.5, -6.6, -16.9, 8.6, 4.9, -7.8, -7.6, 0.0, 0.0, 0.0, 0.0},
|
||||
{5.7, 8.5, 2.0, -9.8, 7.6, -7.0, -2.0, 9.2, -2.2, -6.6, 0.0, 0.0, 0.0},
|
||||
{-2.2, -5.7, 1.6, -3.7, -0.6, 4.1, 2.2, 2.2, 4.6, 2.3, 0.1, 0.0, 0.0},
|
||||
{3.3, -1.1, -2.4, 2.6, -1.3, -1.7, -0.6, 0.4, 0.7, -0.3, 2.3, 4.2, 0.0},
|
||||
{-1.5, -0.2, -0.3, 0.5, 0.2, 0.9, -1.4, 0.6, -0.6, -1.0, -0.3, 0.3, 0.4},
|
||||
{-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
|
||||
{-2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
|
||||
{2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
|
||||
{-2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1},
|
||||
};
|
||||
|
||||
static double hnm_wmm2000[13][13]=
|
||||
static double hnm_wmm2005[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 5194.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2484.8, -467.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -224.7, 293.0, -486.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 273.3, -227.9, 120.9, -302.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 42.0, 173.8, -135.0, -38.6, 105.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -17.4, 61.2, 63.2, -62.9, 0.2, 43.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -62.3, -24.5, 8.9, 23.4, 15.0, -27.6, -7.8, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 12.4, -20.8, 8.4, -21.2, 15.5, 9.1, -15.5, -5.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.4, 13.9, 12.0, -6.2, -8.6, 9.4, 5.0, -8.4, 3.2, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.9, -0.7, 3.9, 4.8, -5.3, -1.0, -2.4, 1.3, -2.3, -6.4, 0.0, 0.0},
|
||||
{0.0, -1.5, 0.7, -1.1, -2.3, 1.3, -0.6, -2.8, -1.6, -0.1, -1.9, 1.4, 0.0},
|
||||
{0.0, -1.0, 0.7, 2.2, -2.5, -0.2, 0.0, -0.2, 0.0, 0.2, -0.9, -0.2, 1.0},
|
||||
{0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
|
||||
{0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
|
||||
{0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8},
|
||||
};
|
||||
|
||||
static double gtnm_wmm2000[13][13]=
|
||||
static double gtnm_wmm2005[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{14.7, 11.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-13.6, -0.7, -1.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.3, -4.3, 0.9, -8.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-1.6, 0.9, -7.6, 2.2, -3.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.9, -0.2, -2.5, -2.7, -0.9, 1.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1.2, 0.2, 1.7, 1.6, -0.1, -0.3, 0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.4, -0.8, -0.2, 1.1, 0.4, 0.0, -0.2, -0.2, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.3, 0.6, -0.8, 0.3, -0.2, 0.5, 0.0, -0.6, 0.1, 0.0, 0.0, 0.0, 0.0},
|
||||
{8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
};
|
||||
|
||||
static double htnm_wmm2000[13][13]=
|
||||
static double htnm_wmm2005[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -21.5, -9.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 6.4, -1.3, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.3, 0.7, 3.7, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 2.1, 2.3, 3.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.3, -1.7, -0.9, -1.0, -0.1, 1.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 1.4, 0.2, 0.7, 0.4, -0.3, -0.8, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.5, 0.1, -0.2, 0.0, 0.1, -0.1, 0.3, 0.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
@@ -186,8 +197,8 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
{
|
||||
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||
int n,m;
|
||||
/* reference dates */
|
||||
long date0_wmm2000 = yymmdd_to_julian_days(0,1,1);
|
||||
/* reference date for current model is 1 januari 2005 */
|
||||
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
|
||||
|
||||
double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
|
||||
double sinpsi, cospsi, inv_s;
|
||||
@@ -272,13 +283,14 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
}
|
||||
}
|
||||
|
||||
/* compute gnm, hnm at dat */
|
||||
/* WMM2000 */
|
||||
yearfrac = (dat - date0_wmm2000) / 365.25;
|
||||
/* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
|
||||
achieved by adjusting the coefficients at time t0 for linear secular variation */
|
||||
/* WMM2005 */
|
||||
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||
for ( n = 1; n <= nmax; n++ ) {
|
||||
for ( m = 0; m <= nmax; m++ ) {
|
||||
gnm[n][m] = gnm_wmm2000[n][m] + yearfrac * gtnm_wmm2000[n][m];
|
||||
hnm[n][m] = hnm_wmm2000[n][m] + yearfrac * htnm_wmm2000[n][m];
|
||||
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +352,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||
int n,m;
|
||||
/* reference dates */
|
||||
long date0_wmm2000 = yymmdd_to_julian_days(0,1,1);
|
||||
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
|
||||
|
||||
double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
|
||||
|
||||
@@ -397,12 +409,12 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
}
|
||||
|
||||
/* compute gnm, hnm at dat */
|
||||
/* WMM2000 */
|
||||
yearfrac = (dat - date0_wmm2000) / 365.25;
|
||||
/* WMM2005 */
|
||||
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||
for ( n = 1; n <= nmax; n++ ) {
|
||||
for ( m = 0; m <= nmax; m++ ) {
|
||||
gnm[n][m] = gnm_wmm2000[n][m] + yearfrac * gtnm_wmm2000[n][m];
|
||||
hnm[n][m] = hnm_wmm2000[n][m] + yearfrac * htnm_wmm2000[n][m];
|
||||
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
includedir = @includedir@/math
|
||||
|
||||
noinst_PROGRAMS = SGMathTest
|
||||
check_PROGRAMS = SGMathTest
|
||||
check_PROGRAMS = SGMathTest SGGeometryTest
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
SGMathTest_SOURCES = SGMathTest.cxx
|
||||
SGMathTest_LDADD = libsgmath.a $(base_LIBS)
|
||||
|
||||
SGGeometryTest_SOURCES = SGGeometryTest.cxx
|
||||
SGGeometryTest_LDADD = libsgmath.a $(base_LIBS)
|
||||
|
||||
lib_LIBRARIES = libsgmath.a
|
||||
|
||||
@@ -20,20 +21,28 @@ include_HEADERS = \
|
||||
sg_random.h \
|
||||
sg_types.hxx \
|
||||
vector.hxx \
|
||||
fastmath.hxx \
|
||||
SGBox.hxx \
|
||||
SGCMath.hxx \
|
||||
SGGeoc.hxx \
|
||||
SGGeod.hxx \
|
||||
SGGeodesy.hxx \
|
||||
SGGeometry.hxx \
|
||||
SGGeometryFwd.hxx \
|
||||
SGIntersect.hxx \
|
||||
SGLimits.hxx \
|
||||
SGLineSegment.hxx \
|
||||
SGMatrix.hxx \
|
||||
SGMath.hxx \
|
||||
SGMathFwd.hxx \
|
||||
SGMisc.hxx \
|
||||
SGPlane.hxx \
|
||||
SGQuat.hxx \
|
||||
SGVec4.hxx \
|
||||
SGVec3.hxx
|
||||
|
||||
|
||||
EXTRA_DIST = linintp2.h linintp2.inl sphrintp.h sphrintp.inl
|
||||
SGRay.hxx \
|
||||
SGSphere.hxx \
|
||||
SGTriangle.hxx \
|
||||
SGVec2.hxx \
|
||||
SGVec3.hxx \
|
||||
SGVec4.hxx
|
||||
|
||||
libsgmath_a_SOURCES = \
|
||||
interpolater.cxx \
|
||||
@@ -42,7 +51,6 @@ libsgmath_a_SOURCES = \
|
||||
sg_geodesy.cxx \
|
||||
sg_random.c \
|
||||
vector.cxx \
|
||||
fastmath.cxx \
|
||||
SGGeodesy.cxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGBox_H
|
||||
#define SGBox_H
|
||||
|
||||
template<typename T>
|
||||
class SGBox {
|
||||
public:
|
||||
SGBox() :
|
||||
_min(SGLimits<T>::max(), SGLimits<T>::max(), SGLimits<T>::max()),
|
||||
_max(-SGLimits<T>::max(), -SGLimits<T>::max(), -SGLimits<T>::max())
|
||||
{ }
|
||||
void setMin(const SGVec3<T>& min)
|
||||
{ _min = min; }
|
||||
const SGVec3<T>& getMin() const
|
||||
{ return _min; }
|
||||
|
||||
void setMax(const SGVec3<T>& max)
|
||||
{ _max = max; }
|
||||
const SGVec3<T>& getMax() const
|
||||
{ return _max; }
|
||||
|
||||
// Only works for floating point types
|
||||
SGVec3<T> getCenter() const
|
||||
{ return T(0.5)*(_min + _max); }
|
||||
|
||||
// Only valid for nonempty boxes
|
||||
SGVec3<T> getSize() const
|
||||
{ return _max - _min; }
|
||||
|
||||
T getVolume() const
|
||||
{
|
||||
if (empty())
|
||||
return 0;
|
||||
return (_max[0] - _min[0])*(_max[1] - _min[1])*(_max[2] - _min[2]);
|
||||
}
|
||||
|
||||
const bool empty() const
|
||||
{ return !valid(); }
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
if (_max[0] < _min[0])
|
||||
return false;
|
||||
if (_max[1] < _min[1])
|
||||
return false;
|
||||
if (_max[2] < _min[2])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_min[0] = SGLimits<T>::max();
|
||||
_min[1] = SGLimits<T>::max();
|
||||
_min[2] = SGLimits<T>::max();
|
||||
_max[0] = -SGLimits<T>::max();
|
||||
_max[1] = -SGLimits<T>::max();
|
||||
_max[2] = -SGLimits<T>::max();
|
||||
}
|
||||
|
||||
void expandBy(const SGVec3<T>& v)
|
||||
{ _min = min(_min, v); _max = max(_max, v); }
|
||||
|
||||
void expandBy(const SGBox<T>& b)
|
||||
{ _min = min(_min, b._min); _max = max(_max, b._max); }
|
||||
|
||||
// Note that this only works if the box is nonmepty
|
||||
unsigned getBroadestAxis() const
|
||||
{
|
||||
SGVec3d size = getSize();
|
||||
if (size[1] <= size[0] && size[2] <= size[0])
|
||||
return 0;
|
||||
else if (size[2] <= size[1])
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
private:
|
||||
SGVec3<T> _min;
|
||||
SGVec3<T> _max;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGBox<T>& box)
|
||||
{ return s << "min = " << box.getMin() << ", max = " << box.getMax(); }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGCMath_H
|
||||
#define SGCMath_H
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
// We have cmath from the standard c++ lib available
|
||||
#include <cmath>
|
||||
#else
|
||||
// We only have math.h with the c89 double functions.
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+27
-20
@@ -27,12 +27,6 @@ class SGGeoc {
|
||||
public:
|
||||
/// Default constructor, initializes the instance to lat = lon = lat = 0
|
||||
SGGeoc(void);
|
||||
/// Initialize from a cartesian vector assumed to be in meters
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
SGGeoc(const SGVec3<double>& cart);
|
||||
/// Initialize from a geodetic position
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
SGGeoc(const SGGeod& geod);
|
||||
|
||||
/// Factory from angular values in radians and radius in ft
|
||||
static SGGeoc fromRadFt(double lon, double lat, double radius);
|
||||
@@ -42,6 +36,13 @@ public:
|
||||
static SGGeoc fromRadM(double lon, double lat, double radius);
|
||||
/// Factory from angular values in degrees and radius in m
|
||||
static SGGeoc fromDegM(double lon, double lat, double radius);
|
||||
/// Factory to convert position from a cartesian position assumed to be
|
||||
/// in wgs84 measured in meters
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGGeoc fromCart(const SGVec3<double>& cart);
|
||||
/// Factory to convert position from a geodetic position
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGGeoc fromGeod(const SGGeod& geod);
|
||||
|
||||
/// Return the geocentric longitude in radians
|
||||
double getLongitudeRad(void) const;
|
||||
@@ -103,20 +104,6 @@ SGGeoc::SGGeoc(double lon, double lat, double radius) :
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeoc::SGGeoc(const SGVec3<double>& cart)
|
||||
{
|
||||
SGGeodesy::SGCartToGeoc(cart, *this);
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeoc::SGGeoc(const SGGeod& geod)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeodToCart(geod, cart);
|
||||
SGGeodesy::SGCartToGeoc(cart, *this);
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeoc
|
||||
SGGeoc::fromRadFt(double lon, double lat, double radius)
|
||||
@@ -165,6 +152,26 @@ SGGeoc::fromDegM(double lon, double lat, double radius)
|
||||
#endif
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeoc
|
||||
SGGeoc::fromCart(const SGVec3<double>& cart)
|
||||
{
|
||||
SGGeoc geoc;
|
||||
SGGeodesy::SGCartToGeoc(cart, geoc);
|
||||
return geoc;
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeoc
|
||||
SGGeoc::fromGeod(const SGGeod& geod)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeodToCart(geod, cart);
|
||||
SGGeoc geoc;
|
||||
SGGeodesy::SGCartToGeoc(cart, geoc);
|
||||
return geoc;
|
||||
}
|
||||
|
||||
inline
|
||||
double
|
||||
SGGeoc::getLongitudeRad(void) const
|
||||
|
||||
+27
-20
@@ -27,12 +27,6 @@ class SGGeod {
|
||||
public:
|
||||
/// Default constructor, initializes the instance to lat = lon = elev = 0
|
||||
SGGeod(void);
|
||||
/// Initialize from a cartesian vector assumed to be in meters
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
SGGeod(const SGVec3<double>& cart);
|
||||
/// Initialize from a geocentric position
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
SGGeod(const SGGeoc& geoc);
|
||||
|
||||
/// Factory from angular values in radians and elevation is 0
|
||||
static SGGeod fromRad(double lon, double lat);
|
||||
@@ -46,6 +40,13 @@ public:
|
||||
static SGGeod fromRadM(double lon, double lat, double elevation);
|
||||
/// Factory from angular values in degrees and elevation in m
|
||||
static SGGeod fromDegM(double lon, double lat, double elevation);
|
||||
/// Factory to convert position from a cartesian position assumed to be
|
||||
/// in wgs84 measured in meters
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGGeod fromCart(const SGVec3<double>& cart);
|
||||
/// Factory to convert position from a geocentric position
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGGeod fromGeoc(const SGGeoc& geoc);
|
||||
|
||||
/// Return the geodetic longitude in radians
|
||||
double getLongitudeRad(void) const;
|
||||
@@ -107,20 +108,6 @@ SGGeod::SGGeod(double lon, double lat, double elevation) :
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeod::SGGeod(const SGVec3<double>& cart)
|
||||
{
|
||||
SGGeodesy::SGCartToGeod(cart, *this);
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeod::SGGeod(const SGGeoc& geoc)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeocToCart(geoc, cart);
|
||||
SGGeodesy::SGCartToGeod(cart, *this);
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeod
|
||||
SGGeod::fromRad(double lon, double lat)
|
||||
@@ -191,6 +178,26 @@ SGGeod::fromDegM(double lon, double lat, double elevation)
|
||||
#endif
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeod
|
||||
SGGeod::fromCart(const SGVec3<double>& cart)
|
||||
{
|
||||
SGGeod geod;
|
||||
SGGeodesy::SGCartToGeod(cart, geod);
|
||||
return geod;
|
||||
}
|
||||
|
||||
inline
|
||||
SGGeod
|
||||
SGGeod::fromGeoc(const SGGeoc& geoc)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeocToCart(geoc, cart);
|
||||
SGGeod geod;
|
||||
SGGeodesy::SGCartToGeod(cart, geod);
|
||||
return geod;
|
||||
}
|
||||
|
||||
inline
|
||||
double
|
||||
SGGeod::getLongitudeRad(void) const
|
||||
|
||||
@@ -18,12 +18,6 @@
|
||||
#ifndef SGGeodesy_H
|
||||
#define SGGeodesy_H
|
||||
|
||||
class SGGeoc;
|
||||
class SGGeod;
|
||||
|
||||
template<typename T>
|
||||
class SGVec3;
|
||||
|
||||
class SGGeodesy {
|
||||
public:
|
||||
// Hard numbers from the WGS84 standard.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGGeometry_HXX
|
||||
#define SGGeometry_HXX
|
||||
|
||||
// Required ...
|
||||
#include "SGMath.hxx"
|
||||
|
||||
// Make sure all is defined
|
||||
#include "SGGeometryFwd.hxx"
|
||||
|
||||
// Geometric primitives we know about
|
||||
#include "SGBox.hxx"
|
||||
#include "SGSphere.hxx"
|
||||
#include "SGRay.hxx"
|
||||
#include "SGLineSegment.hxx"
|
||||
#include "SGPlane.hxx"
|
||||
#include "SGTriangle.hxx"
|
||||
|
||||
// Intersection tests
|
||||
#include "SGIntersect.hxx"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGGeometryFwd_HXX
|
||||
#define SGGeometryFwd_HXX
|
||||
|
||||
template<typename T>
|
||||
class SGBox;
|
||||
typedef SGBox<float> SGBoxf;
|
||||
typedef SGBox<double> SGBoxd;
|
||||
|
||||
template<typename T>
|
||||
class SGSphere;
|
||||
typedef SGSphere<float> SGSpheref;
|
||||
typedef SGSphere<double> SGSphered;
|
||||
|
||||
template<typename T>
|
||||
class SGRay;
|
||||
typedef SGRay<float> SGRayf;
|
||||
typedef SGRay<double> SGRayd;
|
||||
|
||||
template<typename T>
|
||||
class SGLineSegment;
|
||||
typedef SGLineSegment<float> SGLineSegmentf;
|
||||
typedef SGLineSegment<double> SGLineSegmentd;
|
||||
|
||||
template<typename T>
|
||||
class SGPlane;
|
||||
typedef SGPlane<float> SGPlanef;
|
||||
typedef SGPlane<double> SGPlaned;
|
||||
|
||||
template<typename T>
|
||||
class SGTriangle;
|
||||
typedef SGTriangle<float> SGTrianglef;
|
||||
typedef SGTriangle<double> SGTriangled;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,442 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "SGGeometry.hxx"
|
||||
#include "sg_random.h"
|
||||
|
||||
template<typename T>
|
||||
SGVec3<T> rndVec3(void)
|
||||
{
|
||||
return SGVec3<T>(sg_random(), sg_random(), sg_random());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
TriangleLineIntersectionTest(void)
|
||||
{
|
||||
unsigned nTests = 100000;
|
||||
unsigned failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGVec3<T> v0 = rndVec3<T>();
|
||||
SGVec3<T> v1 = rndVec3<T>();
|
||||
SGVec3<T> v2 = rndVec3<T>();
|
||||
|
||||
SGTriangle<T> tri(v0, v1, v2);
|
||||
|
||||
// generate random coeficients
|
||||
T u = 4*sg_random() - 2;
|
||||
T v = 4*sg_random() - 2;
|
||||
T t = 4*sg_random() - 2;
|
||||
|
||||
SGVec3<T> isectpt = v0 + u*(v1 - v0) + v*(v2 - v0);
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
SGVec3<T> dir = rndVec3<T>();
|
||||
|
||||
SGVec3<T> isectres;
|
||||
lineSegment.set(isectpt - t*dir, isectpt + (1 - t)*dir);
|
||||
|
||||
if (intersects(isectres, tri, lineSegment)) {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
|
||||
if (!equivalent(isectres, isectpt)) {
|
||||
std::cout << "Failed line segment intersection test #" << i
|
||||
<< ": not equivalent!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Failed line segment intersection test #" << i
|
||||
<< ": false positive!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
|
||||
std::cout << "Failed line segment intersection test #" << i
|
||||
<< ": false negative!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(isectpt - t*dir, dir);
|
||||
if (intersects(isectres, tri, ray)) {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
|
||||
if (!equivalent(isectres, isectpt)) {
|
||||
std::cout << "Failed ray intersection test #" << i
|
||||
<< ": not equivalent!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Failed ray intersection test #" << i
|
||||
<< ": false positive!\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
|
||||
std::cout << "Failed ray intersection test #" << i
|
||||
<< ": false negative !\nu = "
|
||||
<< u << ", v = " << v << ", t = " << t
|
||||
<< "\n" << tri << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed ray intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Some crude handmade test
|
||||
SGVec3<T> v0 = SGVec3<T>(0, 0, 0);
|
||||
SGVec3<T> v1 = SGVec3<T>(1, 0, 0);
|
||||
SGVec3<T> v2 = SGVec3<T>(0, 1, 0);
|
||||
|
||||
SGTriangle<T> tri(v0, v1, v2);
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
|
||||
if (!intersects(tri, ray)) {
|
||||
std::cout << "Failed test #1!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
|
||||
if (!intersects(tri, ray)) {
|
||||
std::cout << "Failed test #2!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #3!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #4!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 1, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #5!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 0, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #6!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -1));
|
||||
if (!intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #7!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// is exactly in the plane
|
||||
// FIXME: cannot detect that yet ??
|
||||
// lineSegment.set(SGVec3<T>(0, 0, 0), SGVec3<T>(1, 0, 0));
|
||||
// if (!intersects(tri, lineSegment)) {
|
||||
// std::cout << "Failed test #8!" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// is exactly in the plane
|
||||
// FIXME: cannot detect that yet ??
|
||||
// lineSegment.set(SGVec3<T>(-1, 0, 0), SGVec3<T>(1, 0, 0));
|
||||
// if (!intersects(tri, lineSegment)) {
|
||||
// std::cout << "Failed test #9!" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// is exactly paralell to the plane
|
||||
// FIXME: cannot detect that yet ??
|
||||
// lineSegment.set(SGVec3<T>(-1, 1, 0), SGVec3<T>(1, 1, 0));
|
||||
// if (intersects(tri, lineSegment)) {
|
||||
// std::cout << "Failed test #10!" << std::endl;
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// should fail since the line segment poins slightly beyond the triangle
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -0.9));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #11!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, -0.1, -1));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #12!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, -0.1, -1));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #13!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, 0, -1));
|
||||
if (intersects(tri, lineSegment)) {
|
||||
std::cout << "Failed test #14!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
SphereLineIntersectionTest(void)
|
||||
{
|
||||
unsigned nTests = 100000;
|
||||
unsigned failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGVec3<T> center = rndVec3<T>();
|
||||
T radius = 2*sg_random();
|
||||
SGSphere<T> sphere(center, radius);
|
||||
|
||||
SGVec3<T> offset = normalize(rndVec3<T>());
|
||||
T t = 4*sg_random();
|
||||
|
||||
// This one is the point we use to judge if the test should fail or not
|
||||
SGVec3<T> base = center + t*offset;
|
||||
|
||||
SGVec3<T> per = perpendicular(offset);
|
||||
SGVec3<T> start = base + 4*sg_random()*per;
|
||||
SGVec3<T> end = base - 4*sg_random()*per;
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(start, end);
|
||||
if (intersects(sphere, lineSegment)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(start, end - start);
|
||||
if (intersects(sphere, ray)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed sphere line intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGVec3<T> center = rndVec3<T>();
|
||||
T radius = 2*sg_random();
|
||||
SGSphere<T> sphere(center, radius);
|
||||
|
||||
SGVec3<T> offset = normalize(rndVec3<T>());
|
||||
T t = 4*sg_random();
|
||||
|
||||
// This one is the point we use to judge if the test should fail or not
|
||||
SGVec3<T> base = center + t*offset;
|
||||
|
||||
SGVec3<T> start = base;
|
||||
SGVec3<T> end = base + 2*sg_random()*offset;
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(start, end);
|
||||
if (intersects(sphere, lineSegment)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(start, end - start);
|
||||
if (intersects(sphere, ray)) {
|
||||
if (radius < t) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false positive!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (t <= radius) {
|
||||
std::cout << "Failed sphere line intersection test #" << i
|
||||
<< ": false negative!\nt = " << t << "\n"
|
||||
<< sphere << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed sphere line intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool
|
||||
BoxLineIntersectionTest(void)
|
||||
{
|
||||
// ok, bad test case coverage, but better than nothing ...
|
||||
|
||||
unsigned nTests = 100000;
|
||||
unsigned failedCount = 0;
|
||||
for (unsigned i = 0; i < nTests; ++i) {
|
||||
SGBox<T> box;
|
||||
box.expandBy(rndVec3<T>());
|
||||
box.expandBy(rndVec3<T>());
|
||||
|
||||
SGVec3<T> center = box.getCenter();
|
||||
|
||||
// This one is the point we use to judge if the test should fail or not
|
||||
SGVec3<T> base = rndVec3<T>();
|
||||
SGVec3<T> dir = base - center;
|
||||
|
||||
SGLineSegment<T> lineSegment;
|
||||
lineSegment.set(base, base + dir);
|
||||
if (intersects(box, lineSegment)) {
|
||||
if (!intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false positive!\n"
|
||||
<< box << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false negative!\n"
|
||||
<< box << "\n" << lineSegment << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
|
||||
SGRay<T> ray;
|
||||
ray.set(base, dir);
|
||||
if (intersects(box, ray)) {
|
||||
if (!intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false positive!\n"
|
||||
<< box << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
} else {
|
||||
if (intersects(box, base)) {
|
||||
std::cout << "Failed box line intersection test #" << i
|
||||
<< ": false negative!\n"
|
||||
<< box << "\n" << ray << std::endl;
|
||||
++failedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nTests < 100*failedCount) {
|
||||
std::cout << "Failed box line intersection tests: " << failedCount
|
||||
<< " tests out of " << nTests
|
||||
<< " went wrong. Abort!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
std::cout << "Testing Geometry intersection routines.\n"
|
||||
<< "Some of these tests can fail due to roundoff problems...\n"
|
||||
<< "Dont worry if only a few of them fail..." << std::endl;
|
||||
|
||||
if (!TriangleLineIntersectionTest<float>())
|
||||
return EXIT_FAILURE;
|
||||
if (!TriangleLineIntersectionTest<double>())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!SphereLineIntersectionTest<float>())
|
||||
return EXIT_FAILURE;
|
||||
if (!SphereLineIntersectionTest<double>())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!BoxLineIntersectionTest<float>())
|
||||
return EXIT_FAILURE;
|
||||
if (!BoxLineIntersectionTest<double>())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
std::cout << "Successfully passed all tests!" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,627 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGIntersect_HXX
|
||||
#define SGIntersect_HXX
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGSphere<T>& sphere)
|
||||
{
|
||||
if (sphere.empty())
|
||||
return false;
|
||||
// Is more or less trivially included in the next tests
|
||||
// if (box.empty())
|
||||
// return false;
|
||||
|
||||
if (sphere.getCenter().x() < box.getMin().x() - sphere.getRadius())
|
||||
return false;
|
||||
if (sphere.getCenter().y() < box.getMin().y() - sphere.getRadius())
|
||||
return false;
|
||||
if (sphere.getCenter().z() < box.getMin().z() - sphere.getRadius())
|
||||
return false;
|
||||
|
||||
if (box.getMax().x() + sphere.getRadius() < sphere.getCenter().x())
|
||||
return false;
|
||||
if (box.getMax().y() + sphere.getRadius() < sphere.getCenter().y())
|
||||
return false;
|
||||
if (box.getMax().z() + sphere.getRadius() < sphere.getCenter().z())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGBox<T>& box)
|
||||
{ return intersects(box, sphere); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGVec3<T>& v, const SGBox<T>& box)
|
||||
{
|
||||
if (v[0] < box.getMin()[0])
|
||||
return false;
|
||||
if (box.getMax()[0] < v[0])
|
||||
return false;
|
||||
if (v[1] < box.getMin()[1])
|
||||
return false;
|
||||
if (box.getMax()[1] < v[1])
|
||||
return false;
|
||||
if (v[2] < box.getMin()[2])
|
||||
return false;
|
||||
if (box.getMax()[2] < v[2])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGVec3<T>& v)
|
||||
{ return intersects(v, box); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGRay<T>& ray, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the ray origin and non nomalized direction.
|
||||
// For 0 <= \alpha the ray intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is ana aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), ray.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the rays origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min())
|
||||
return true;
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), ray.getDirection());
|
||||
|
||||
// If we get here, we already know that the rays origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a ray paralell to the plane. That is no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, check equation multiplied by
|
||||
// the denominator.
|
||||
T alphaDen = copysign(1, den)*num;
|
||||
if (alphaDen < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGPlane<T>& plane, const SGRay<T>& ray)
|
||||
{ return intersects(ray, plane); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGRay<T>& ray, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the ray origin and non nomalized direction.
|
||||
// For 0 <= \alpha the ray intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is ana aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), ray.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the rays origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min()) {
|
||||
dst = ray.getOrigin();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), ray.getDirection());
|
||||
|
||||
// If we get here, we already know that the rays origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a ray paralell to the plane. That is no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, check equation multiplied by
|
||||
// the denominator.
|
||||
T alpha = num/den;
|
||||
if (alpha < 0)
|
||||
return false;
|
||||
|
||||
dst = ray.getOrigin() + alpha*ray.getDirection();
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGRay<T>& ray)
|
||||
{ return intersects(dst, ray, plane); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the line segments origin and non nomalized direction.
|
||||
// For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is ana aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), lineSegment.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the lines origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min())
|
||||
return true;
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), lineSegment.getDirection());
|
||||
|
||||
// If we get here, we already know that the lines origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a line paralell to the plane. That is no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, compare equations
|
||||
// multiplied by |den|. Note that copysign is usually a compiler intrinsic
|
||||
// that expands in assembler code that not even stalls the cpus pipes.
|
||||
T alphaDen = copysign(1, den)*num;
|
||||
if (alphaDen < 0)
|
||||
return false;
|
||||
if (den < alphaDen)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
|
||||
{ return intersects(lineSegment, plane); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
|
||||
{
|
||||
// We compute the intersection point
|
||||
// x = origin + \alpha*direction
|
||||
// from the line segments origin and non nomalized direction.
|
||||
// For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
|
||||
// The intersection point x can also be written
|
||||
// x = n*dist + y
|
||||
// where n is the planes normal, dist is the distance of the plane from
|
||||
// the origin in normal direction and y is an aproriate vector
|
||||
// perpendicular to n.
|
||||
// Equate the x values and take the scalar product with the plane normal n.
|
||||
// dot(n, origin) + \alpha*dot(n, direction) = dist
|
||||
// We can now compute alpha from the above equation.
|
||||
// \alpha = (dist - dot(n, origin))/dot(n, direction)
|
||||
|
||||
// The negative numerator for the \alpha expression
|
||||
T num = plane.getPositiveDist();
|
||||
num -= dot(plane.getNormal(), lineSegment.getOrigin());
|
||||
|
||||
// If the numerator is zero, we have the lines origin included in the plane
|
||||
if (fabs(num) <= SGLimits<T>::min()) {
|
||||
dst = lineSegment.getOrigin();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The denominator for the \alpha expression
|
||||
T den = dot(plane.getNormal(), lineSegment.getDirection());
|
||||
|
||||
// If we get here, we already know that the lines origin is not included
|
||||
// in the plane. Thus if we have a zero denominator we have
|
||||
// a line paralell to the plane. That is: no intersection.
|
||||
if (fabs(den) <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
// We would now compute \alpha = num/den and compare with 0 and 1.
|
||||
// But to avoid that expensive division, check equation multiplied by
|
||||
// the denominator. FIXME: shall we do so? or compute like that?
|
||||
T alpha = num/den;
|
||||
if (alpha < 0)
|
||||
return false;
|
||||
if (1 < alpha)
|
||||
return false;
|
||||
|
||||
dst = lineSegment.getOrigin() + alpha*lineSegment.getDirection();
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
|
||||
{ return intersects(dst, lineSegment, plane); }
|
||||
|
||||
|
||||
// Distance of a line segment to a point
|
||||
template<typename T>
|
||||
inline T
|
||||
distSqr(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
|
||||
{
|
||||
SGVec3<T> ps = p - lineSeg.getStart();
|
||||
|
||||
T psdotdir = dot(ps, lineSeg.getDirection());
|
||||
if (psdotdir <= 0)
|
||||
return dot(ps, ps);
|
||||
|
||||
SGVec3<T> pe = p - lineSeg.getEnd();
|
||||
if (0 <= dot(pe, lineSeg.getDirection()))
|
||||
return dot(pe, pe);
|
||||
|
||||
return dot(ps, ps) - psdotdir*psdotdir/dot(lineSeg.getDirection(), lineSeg.getDirection());
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline T
|
||||
distSqr(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
|
||||
{ return distSqr(lineSeg, p); }
|
||||
// with sqrt
|
||||
template<typename T>
|
||||
inline T
|
||||
dist(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
|
||||
{ return sqrt(distSqr(lineSeg, p)); }
|
||||
template<typename T>
|
||||
inline T
|
||||
dist(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
|
||||
{ return sqrt(distSqr(lineSeg, p)); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGRay<T>& ray, const SGSphere<T>& sphere)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
|
||||
// second edition, page 571
|
||||
SGVec3<T> l = sphere.getCenter() - ray.getOrigin();
|
||||
T s = dot(l, ray.getDirection());
|
||||
T l2 = dot(l, l);
|
||||
|
||||
T r2 = sphere.getRadius2();
|
||||
if (s < 0 && l2 > r2)
|
||||
return false;
|
||||
|
||||
T d2 = dot(ray.getDirection(), ray.getDirection());
|
||||
// The original test would read
|
||||
// T m2 = l2 - s*s/d2;
|
||||
// if (m2 > r2)
|
||||
// return false;
|
||||
// but to avoid the expensive division, we multiply by d2
|
||||
T m2 = d2*l2 - s*s;
|
||||
if (m2 > d2*r2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGRay<T>& ray)
|
||||
{ return intersects(ray, sphere); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGLineSegment<T>& lineSegment, const SGSphere<T>& sphere)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
|
||||
// second edition, page 571
|
||||
SGVec3<T> l = sphere.getCenter() - lineSegment.getStart();
|
||||
T ld = length(lineSegment.getDirection());
|
||||
T s = dot(l, lineSegment.getDirection())/ld;
|
||||
T l2 = dot(l, l);
|
||||
|
||||
T r2 = sphere.getRadius2();
|
||||
if (s < 0 && l2 > r2)
|
||||
return false;
|
||||
|
||||
T m2 = l2 - s*s;
|
||||
if (m2 > r2)
|
||||
return false;
|
||||
|
||||
T q = sqrt(r2 - m2);
|
||||
T t = s - q;
|
||||
if (ld < t)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGLineSegment<T>& lineSegment)
|
||||
{ return intersects(lineSegment, sphere); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
// FIXME do not use that default argument later. Just for development now
|
||||
intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
// Method based on the observation that we are looking for a
|
||||
// point x that can be expressed in terms of the triangle points
|
||||
// x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
|
||||
// with 0 <= u, v and u + v <= 1.
|
||||
// OTOH it could be expressed in terms of the ray
|
||||
// x = o + t*d
|
||||
// Now we can compute u, v and t.
|
||||
SGVec3<T> p = cross(ray.getDirection(), tri.getEdge(1));
|
||||
|
||||
T denom = dot(p, tri.getEdge(0));
|
||||
T signDenom = copysign(1, denom);
|
||||
|
||||
SGVec3<T> s = ray.getOrigin() - tri.getBaseVertex();
|
||||
SGVec3<T> q = cross(s, tri.getEdge(0));
|
||||
// Now t would read
|
||||
// t = 1/denom*dot(q, tri.getEdge(1));
|
||||
// To avoid an expensive division we multiply by |denom|
|
||||
T tDenom = signDenom*dot(q, tri.getEdge(1));
|
||||
if (tDenom < 0)
|
||||
return false;
|
||||
// For line segment we would test against
|
||||
// if (1 < t)
|
||||
// return false;
|
||||
// with the original t. The multiplied test would read
|
||||
// if (absDenom < tDenom)
|
||||
// return false;
|
||||
|
||||
T absDenom = fabs(denom);
|
||||
T absDenomEps = absDenom*eps;
|
||||
|
||||
// T u = 1/denom*dot(p, s);
|
||||
T u = signDenom*dot(p, s);
|
||||
if (u < -absDenomEps)
|
||||
return false;
|
||||
// T v = 1/denom*dot(q, d);
|
||||
// if (v < -eps)
|
||||
// return false;
|
||||
T v = signDenom*dot(q, ray.getDirection());
|
||||
if (v < -absDenomEps)
|
||||
return false;
|
||||
|
||||
if (u + v > absDenom + absDenomEps)
|
||||
return false;
|
||||
|
||||
// return if paralell ??? FIXME what if paralell and in plane?
|
||||
// may be we are ok below than anyway??
|
||||
if (absDenom <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
x = ray.getOrigin();
|
||||
// if we have survived here it could only happen with denom == 0
|
||||
// that the point is already in plane. Then return the origin ...
|
||||
if (SGLimitsd::min() < absDenom)
|
||||
x += (tDenom/absDenom)*ray.getDirection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
|
||||
{
|
||||
// FIXME: for now just wrap the other method. When that has prooven
|
||||
// well optimized, implement that special case
|
||||
SGVec3<T> dummy;
|
||||
return intersects(dummy, tri, ray, eps);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
// FIXME do not use that default argument later. Just for development now
|
||||
intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
// Method based on the observation that we are looking for a
|
||||
// point x that can be expressed in terms of the triangle points
|
||||
// x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
|
||||
// with 0 <= u, v and u + v <= 1.
|
||||
// OTOH it could be expressed in terms of the lineSegment
|
||||
// x = o + t*d
|
||||
// Now we can compute u, v and t.
|
||||
SGVec3<T> p = cross(lineSegment.getDirection(), tri.getEdge(1));
|
||||
|
||||
T denom = dot(p, tri.getEdge(0));
|
||||
T signDenom = copysign(1, denom);
|
||||
|
||||
SGVec3<T> s = lineSegment.getStart() - tri.getBaseVertex();
|
||||
SGVec3<T> q = cross(s, tri.getEdge(0));
|
||||
// Now t would read
|
||||
// t = 1/denom*dot(q, tri.getEdge(1));
|
||||
// To avoid an expensive division we multiply by |denom|
|
||||
T tDenom = signDenom*dot(q, tri.getEdge(1));
|
||||
if (tDenom < 0)
|
||||
return false;
|
||||
// For line segment we would test against
|
||||
// if (1 < t)
|
||||
// return false;
|
||||
// with the original t. The multiplied test reads
|
||||
T absDenom = fabs(denom);
|
||||
if (absDenom < tDenom)
|
||||
return false;
|
||||
|
||||
// take the CPU accuracy in account
|
||||
T absDenomEps = absDenom*eps;
|
||||
|
||||
// T u = 1/denom*dot(p, s);
|
||||
T u = signDenom*dot(p, s);
|
||||
if (u < -absDenomEps)
|
||||
return false;
|
||||
// T v = 1/denom*dot(q, d);
|
||||
// if (v < -eps)
|
||||
// return false;
|
||||
T v = signDenom*dot(q, lineSegment.getDirection());
|
||||
if (v < -absDenomEps)
|
||||
return false;
|
||||
|
||||
if (u + v > absDenom + absDenomEps)
|
||||
return false;
|
||||
|
||||
// return if paralell ??? FIXME what if paralell and in plane?
|
||||
// may be we are ok below than anyway??
|
||||
if (absDenom <= SGLimits<T>::min())
|
||||
return false;
|
||||
|
||||
x = lineSegment.getStart();
|
||||
// if we have survived here it could only happen with denom == 0
|
||||
// that the point is already in plane. Then return the origin ...
|
||||
if (SGLimitsd::min() < absDenom)
|
||||
x += (tDenom/absDenom)*lineSegment.getDirection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
|
||||
{
|
||||
// FIXME: for now just wrap the othr method. When that has prooven
|
||||
// well optimized, implement that special case
|
||||
SGVec3<T> dummy;
|
||||
return intersects(dummy, tri, lineSegment, eps);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGVec3<T>& v, const SGSphere<T>& sphere)
|
||||
{
|
||||
if (sphere.empty())
|
||||
return false;
|
||||
return distSqr(v, sphere.getCenter()) <= sphere.getRadius2();
|
||||
}
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGSphere<T>& sphere, const SGVec3<T>& v)
|
||||
{ return intersects(v, sphere); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGLineSegment<T>& lineSegment)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
SGVec3<T> c = lineSegment.getCenter() - box.getCenter();
|
||||
SGVec3<T> w = 0.5*lineSegment.getDirection();
|
||||
SGVec3<T> v(fabs(w.x()), fabs(w.y()), fabs(w.z()));
|
||||
SGVec3<T> h = 0.5*box.getSize();
|
||||
|
||||
if (fabs(c[0]) > v[0] + h[0])
|
||||
return false;
|
||||
if (fabs(c[1]) > v[1] + h[1])
|
||||
return false;
|
||||
if (fabs(c[2]) > v[2] + h[2])
|
||||
return false;
|
||||
|
||||
if (fabs(c[1]*w[2] - c[2]*w[1]) > h[1]*v[2] + h[2]*v[1])
|
||||
return false;
|
||||
if (fabs(c[0]*w[2] - c[2]*w[0]) > h[0]*v[2] + h[2]*v[0])
|
||||
return false;
|
||||
if (fabs(c[0]*w[1] - c[1]*w[0]) > h[0]*v[1] + h[1]*v[0])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGLineSegment<T>& lineSegment, const SGBox<T>& box)
|
||||
{ return intersects(box, lineSegment); }
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGBox<T>& box, const SGRay<T>& ray)
|
||||
{
|
||||
// See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
|
||||
|
||||
for (unsigned i = 0; i < 3; ++i) {
|
||||
T cMin = box.getMin()[i];
|
||||
T cMax = box.getMax()[i];
|
||||
|
||||
T cOrigin = ray.getOrigin()[i];
|
||||
|
||||
T cDir = ray.getDirection()[i];
|
||||
if (fabs(cDir) <= SGLimits<T>::min()) {
|
||||
if (cOrigin < cMin)
|
||||
return false;
|
||||
if (cMax < cOrigin)
|
||||
return false;
|
||||
}
|
||||
|
||||
T nearr = - SGLimits<T>::max();
|
||||
T farr = SGLimits<T>::max();
|
||||
|
||||
T T1 = (cMin - cOrigin) / cDir;
|
||||
T T2 = (cMax - cOrigin) / cDir;
|
||||
if (T1 > T2) std::swap (T1, T2);/* since T1 intersection with near plane */
|
||||
if (T1 > nearr) nearr = T1; /* want largest Tnear */
|
||||
if (T2 < farr) farr = T2; /* want smallest Tfarr */
|
||||
if (nearr > farr) // farr box is missed
|
||||
return false;
|
||||
if (farr < 0) // box is behind ray
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// make it symmetric
|
||||
template<typename T>
|
||||
inline bool
|
||||
intersects(const SGRay<T>& ray, const SGBox<T>& box)
|
||||
{ return intersects(box, ray); }
|
||||
|
||||
#endif
|
||||
@@ -26,7 +26,4 @@
|
||||
template<typename T>
|
||||
class SGLimits : public std::numeric_limits<T> {};
|
||||
|
||||
typedef SGLimits<float> SGLimitsf;
|
||||
typedef SGLimits<double> SGLimitsd;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGLineSegment_H
|
||||
#define SGLineSegment_H
|
||||
|
||||
template<typename T>
|
||||
class SGLineSegment {
|
||||
public:
|
||||
SGLineSegment()
|
||||
{ }
|
||||
SGLineSegment(const SGVec3<T>& start, const SGVec3<T>& end) :
|
||||
_start(start),
|
||||
_direction(end - start)
|
||||
{ }
|
||||
|
||||
void set(const SGVec3<T>& start, const SGVec3<T>& end)
|
||||
{ _start = start; _direction = end - start; }
|
||||
|
||||
const SGVec3<T>& getStart() const
|
||||
{ return _start; }
|
||||
SGVec3<T> getEnd() const
|
||||
{ return _start + _direction; }
|
||||
const SGVec3<T>& getDirection() const
|
||||
{ return _direction; }
|
||||
SGVec3<T> getNormalizedDirection() const
|
||||
{ return normalize(getDirection()); }
|
||||
|
||||
SGVec3<T> getCenter() const
|
||||
{ return _start + T(0.5)*_direction; }
|
||||
|
||||
private:
|
||||
SGVec3<T> _start;
|
||||
SGVec3<T> _direction;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGLineSegment<T>& lineSegment)
|
||||
{
|
||||
return s << "line segment: start = " << lineSegment.getStart()
|
||||
<< ", end = " << lineSegment.getEnd();
|
||||
}
|
||||
|
||||
#endif
|
||||
+11
-2
@@ -21,15 +21,24 @@
|
||||
/// Just include them all
|
||||
|
||||
#include <iosfwd>
|
||||
// FIXME, make it compile on IRIX
|
||||
#include <osg/GL>
|
||||
#undef GLUT_APIENTRY_DEFINED // GL/glut.h undef APIENTRY when this symbol is defined. osg/GL defines it (?).
|
||||
// This probably would work if we didn't use plib/pu.h that include GL/glut.h
|
||||
// on its side.
|
||||
|
||||
#include "SGMathFwd.hxx"
|
||||
|
||||
#include "SGCMath.hxx"
|
||||
#include "SGLimits.hxx"
|
||||
#include "SGMisc.hxx"
|
||||
#include "SGGeodesy.hxx"
|
||||
#include "SGVec2.hxx"
|
||||
#include "SGVec3.hxx"
|
||||
#include "SGVec4.hxx"
|
||||
#include "SGQuat.hxx"
|
||||
#include "SGMatrix.hxx"
|
||||
#include "SGGeoc.hxx"
|
||||
#include "SGGeod.hxx"
|
||||
#include "SGQuat.hxx"
|
||||
#include "SGMatrix.hxx"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGMathFwd_H
|
||||
#define SGMathFwd_H
|
||||
|
||||
// All forward declarations in case they only need to be declared
|
||||
|
||||
class SGGeoc;
|
||||
class SGGeod;
|
||||
|
||||
template<typename T>
|
||||
class SGLimits;
|
||||
template<typename T>
|
||||
class SGMatrix;
|
||||
template<typename T>
|
||||
class SGMisc;
|
||||
template<typename T>
|
||||
class SGQuat;
|
||||
template<typename T>
|
||||
class SGVec2;
|
||||
template<typename T>
|
||||
class SGVec3;
|
||||
template<typename T>
|
||||
class SGVec4;
|
||||
|
||||
typedef SGLimits<float> SGLimitsf;
|
||||
typedef SGLimits<double> SGLimitsd;
|
||||
typedef SGMatrix<float> SGMatrixf;
|
||||
typedef SGMatrix<double> SGMatrixd;
|
||||
typedef SGMisc<float> SGMiscf;
|
||||
typedef SGMisc<double> SGMiscd;
|
||||
typedef SGQuat<float> SGQuatf;
|
||||
typedef SGQuat<double> SGQuatd;
|
||||
typedef SGVec2<float> SGVec2f;
|
||||
typedef SGVec2<double> SGVec2d;
|
||||
typedef SGVec3<float> SGVec3f;
|
||||
typedef SGVec3<double> SGVec3d;
|
||||
typedef SGVec4<float> SGVec4f;
|
||||
typedef SGVec4<double> SGVec4d;
|
||||
|
||||
#endif
|
||||
@@ -174,7 +174,9 @@ MatrixTest(void)
|
||||
// Create some test matrix
|
||||
SGVec3<T> v0(2, 7, 17);
|
||||
SGQuat<T> q0 = SGQuat<T>::fromAngleAxis(SGMisc<T>::pi(), normalize(v0));
|
||||
SGMatrix<T> m0(q0, v0);
|
||||
SGMatrix<T> m0;
|
||||
m0.postMultTranslate(v0);
|
||||
m0.postMultRotate(q0);
|
||||
|
||||
// Check the tqo forms of the inverse for that kind of special matrix
|
||||
SGMatrix<T> m1, m2;
|
||||
@@ -213,16 +215,16 @@ GeodesyTest(void)
|
||||
geod0 = SGGeod::fromDegM(30, 20, 17);
|
||||
|
||||
// Test the conversion routines to cartesian coordinates
|
||||
cart0 = geod0;
|
||||
geod1 = cart0;
|
||||
cart0 = SGVec3<double>::fromGeod(geod0);
|
||||
geod1 = SGGeod::fromCart(cart0);
|
||||
if (epsDeg < fabs(geod0.getLongitudeDeg() - geod1.getLongitudeDeg()) ||
|
||||
epsDeg < fabs(geod0.getLatitudeDeg() - geod1.getLatitudeDeg()) ||
|
||||
epsM < fabs(geod0.getElevationM() - geod1.getElevationM()))
|
||||
return false;
|
||||
|
||||
// Test the conversion routines to radial coordinates
|
||||
geoc0 = cart0;
|
||||
cart1 = geoc0;
|
||||
geoc0 = SGGeoc::fromCart(cart0);
|
||||
cart1 = SGVec3<double>::fromGeoc(geoc0);
|
||||
if (!equivalent(cart0, cart1))
|
||||
return false;
|
||||
|
||||
@@ -236,7 +238,9 @@ sgInterfaceTest(void)
|
||||
SGVec3f v3f = SGVec3f::e2();
|
||||
SGVec4f v4f = SGVec4f::e2();
|
||||
SGQuatf qf = SGQuatf::fromEulerRad(1.2, 1.3, -0.4);
|
||||
SGMatrixf mf(qf, v3f);
|
||||
SGMatrixf mf;
|
||||
mf.postMultTranslate(v3f);
|
||||
mf.postMultRotate(qf);
|
||||
|
||||
// Copy to and from plibs types check if result is equal,
|
||||
// test for exact equality
|
||||
@@ -283,7 +287,9 @@ sgdInterfaceTest(void)
|
||||
SGVec3d v3d = SGVec3d::e2();
|
||||
SGVec4d v4d = SGVec4d::e2();
|
||||
SGQuatd qd = SGQuatd::fromEulerRad(1.2, 1.3, -0.4);
|
||||
SGMatrixd md(qd, v3d);
|
||||
SGMatrixd md;
|
||||
md.postMultTranslate(v3d);
|
||||
md.postMultRotate(qd);
|
||||
|
||||
// Copy to and from plibs types check if result is equal,
|
||||
// test for exact equality
|
||||
@@ -346,8 +352,8 @@ main(void)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Check geodetic/geocentric/cartesian conversions
|
||||
// if (!GeodesyTest())
|
||||
// return EXIT_FAILURE;
|
||||
if (!GeodesyTest())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Check interaction with sg*/sgd*
|
||||
if (!sgInterfaceTest())
|
||||
|
||||
+54
-40
@@ -22,9 +22,6 @@
|
||||
template<typename T>
|
||||
struct TransNegRef;
|
||||
|
||||
template<typename T>
|
||||
class SGMatrix;
|
||||
|
||||
/// 3D Matrix Class
|
||||
template<typename T>
|
||||
class SGMatrix {
|
||||
@@ -66,14 +63,13 @@ public:
|
||||
}
|
||||
|
||||
/// Constructor, build up a SGMatrix from a translation
|
||||
SGMatrix(const SGVec3<T>& trans)
|
||||
template<typename S>
|
||||
SGMatrix(const SGVec3<S>& trans)
|
||||
{ set(trans); }
|
||||
|
||||
/// Constructor, build up a SGMatrix from a rotation and a translation
|
||||
SGMatrix(const SGQuat<T>& quat, const SGVec3<T>& trans)
|
||||
{ set(quat, trans); }
|
||||
/// Constructor, build up a SGMatrix from a rotation and a translation
|
||||
SGMatrix(const SGQuat<T>& quat)
|
||||
template<typename S>
|
||||
SGMatrix(const SGQuat<S>& quat)
|
||||
{ set(quat); }
|
||||
|
||||
/// Copy constructor for a transposed negated matrix
|
||||
@@ -81,39 +77,22 @@ public:
|
||||
{ set(tm); }
|
||||
|
||||
/// Set from a tranlation
|
||||
void set(const SGVec3<T>& trans)
|
||||
template<typename S>
|
||||
void set(const SGVec3<S>& trans)
|
||||
{
|
||||
_data.flat[0] = 1; _data.flat[4] = 0;
|
||||
_data.flat[8] = 0; _data.flat[12] = -trans(0);
|
||||
_data.flat[8] = 0; _data.flat[12] = T(trans(0));
|
||||
_data.flat[1] = 0; _data.flat[5] = 1;
|
||||
_data.flat[9] = 0; _data.flat[13] = -trans(1);
|
||||
_data.flat[9] = 0; _data.flat[13] = T(trans(1));
|
||||
_data.flat[2] = 0; _data.flat[6] = 0;
|
||||
_data.flat[10] = 1; _data.flat[14] = -trans(2);
|
||||
_data.flat[10] = 1; _data.flat[14] = T(trans(2));
|
||||
_data.flat[3] = 0; _data.flat[7] = 0;
|
||||
_data.flat[11] = 0; _data.flat[15] = 1;
|
||||
}
|
||||
|
||||
/// Set from a scale/rotation and tranlation
|
||||
void set(const SGQuat<T>& quat, const SGVec3<T>& trans)
|
||||
{
|
||||
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
|
||||
T xx = x*x; T yy = y*y; T zz = z*z;
|
||||
T wx = w*x; T wy = w*y; T wz = w*z;
|
||||
T xy = x*y; T xz = x*z; T yz = y*z;
|
||||
_data.flat[0] = 1-2*(yy+zz); _data.flat[1] = 2*(xy-wz);
|
||||
_data.flat[2] = 2*(xz+wy); _data.flat[3] = 0;
|
||||
_data.flat[4] = 2*(xy+wz); _data.flat[5] = 1-2*(xx+zz);
|
||||
_data.flat[6] = 2*(yz-wx); _data.flat[7] = 0;
|
||||
_data.flat[8] = 2*(xz-wy); _data.flat[9] = 2*(yz+wx);
|
||||
_data.flat[10] = 1-2*(xx+yy); _data.flat[11] = 0;
|
||||
// Well, this one is ugly here, as that xform method on the current
|
||||
// object needs the above data to be already set ...
|
||||
SGVec3<T> t = xformVec(trans);
|
||||
_data.flat[12] = -t(0); _data.flat[13] = -t(1);
|
||||
_data.flat[14] = -t(2); _data.flat[15] = 1;
|
||||
}
|
||||
/// Set from a scale/rotation and tranlation
|
||||
void set(const SGQuat<T>& quat)
|
||||
template<typename S>
|
||||
void set(const SGQuat<S>& quat)
|
||||
{
|
||||
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
|
||||
T xx = x*x; T yy = y*y; T zz = z*z;
|
||||
@@ -202,6 +181,45 @@ public:
|
||||
/// Inplace matrix multiplication, post multiply
|
||||
SGMatrix& operator*=(const SGMatrix<T>& m2);
|
||||
|
||||
template<typename S>
|
||||
SGMatrix& preMultTranslate(const SGVec3<S>& t)
|
||||
{
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols-1; ++i)
|
||||
(*this)(i,3) += T(t(i));
|
||||
return *this;
|
||||
}
|
||||
template<typename S>
|
||||
SGMatrix& postMultTranslate(const SGVec3<S>& t)
|
||||
{
|
||||
SGVec4<T> col3((*this)(0,3), (*this)(1,3), (*this)(2,3), (*this)(3,3));
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols-1; ++i) {
|
||||
SGVec4<T> tmp((*this)(0,3), (*this)(1,3), (*this)(2,3), (*this)(3,3));
|
||||
col3 += T(t(i))*tmp;
|
||||
}
|
||||
(*this)(0,3) = col3(0); (*this)(1,3) = col3(1);
|
||||
(*this)(2,3) = col3(2); (*this)(3,3) = col3(3);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SGMatrix& preMultRotate(const SGQuat<T>& r)
|
||||
{
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols; ++i) {
|
||||
SGVec3<T> col((*this)(0,i), (*this)(1,i), (*this)(2,i));
|
||||
col = r.transform(col);
|
||||
(*this)(0,i) = col(0); (*this)(1,i) = col(1); (*this)(2,i) = col(2);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SGMatrix& postMultRotate(const SGQuat<T>& r)
|
||||
{
|
||||
for (unsigned i = 0; i < SGMatrix<T>::nCols; ++i) {
|
||||
SGVec3<T> col((*this)(i,0), (*this)(i,1), (*this)(i,2));
|
||||
col = r.backTransform(col);
|
||||
(*this)(i,0) = col(0); (*this)(i,1) = col(1); (*this)(i,2) = col(2);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SGVec3<T> xformPt(const SGVec3<T>& pt) const
|
||||
{
|
||||
SGVec3<T> tpt;
|
||||
@@ -571,18 +589,14 @@ operator<<(std::basic_ostream<char_type, traits_type>& s, const SGMatrix<T>& m)
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Two classes doing actually the same on different types
|
||||
typedef SGMatrix<float> SGMatrixf;
|
||||
typedef SGMatrix<double> SGMatrixd;
|
||||
|
||||
inline
|
||||
SGMatrixf
|
||||
toMatrixf(const SGMatrixd& m)
|
||||
{
|
||||
return SGMatrixf((float)m(0,0), (float)m(0,1), (float)m(0,2), (float)m(0,3),
|
||||
(float)m(1,0), (float)m(1,1), (float)m(1,2), (float)m(1,3),
|
||||
(float)m(3,0), (float)m(2,1), (float)m(2,2), (float)m(2,3),
|
||||
(float)m(4,0), (float)m(4,1), (float)m(4,2), (float)m(4,3));
|
||||
(float)m(2,0), (float)m(2,1), (float)m(2,2), (float)m(2,3),
|
||||
(float)m(3,0), (float)m(3,1), (float)m(3,2), (float)m(3,3));
|
||||
}
|
||||
|
||||
inline
|
||||
@@ -591,8 +605,8 @@ toMatrixd(const SGMatrixf& m)
|
||||
{
|
||||
return SGMatrixd(m(0,0), m(0,1), m(0,2), m(0,3),
|
||||
m(1,0), m(1,1), m(1,2), m(1,3),
|
||||
m(3,0), m(2,1), m(2,2), m(2,3),
|
||||
m(4,0), m(4,1), m(4,2), m(4,3));
|
||||
m(2,0), m(2,1), m(2,2), m(2,3),
|
||||
m(3,0), m(3,1), m(3,2), m(3,3));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+38
-5
@@ -18,12 +18,12 @@
|
||||
#ifndef SGMisc_H
|
||||
#define SGMisc_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
template<typename T>
|
||||
class SGMisc {
|
||||
public:
|
||||
static T pi() { return T(3.1415926535897932384626433832795029L); }
|
||||
static T twopi() { return 2*T(3.1415926535897932384626433832795029L); }
|
||||
|
||||
static T min(const T& a, const T& b)
|
||||
{ return a < b ? a : b; }
|
||||
static T min(const T& a, const T& b, const T& c)
|
||||
@@ -36,6 +36,11 @@ public:
|
||||
{ return max(max(a, b), c); }
|
||||
static T max(const T& a, const T& b, const T& c, const T& d)
|
||||
{ return max(max(max(a, b), c), d); }
|
||||
|
||||
// clip the value of a to be in the range between and including _min and _max
|
||||
static T clip(const T& a, const T& _min, const T& _max)
|
||||
{ return max(_min, min(_max, a)); }
|
||||
|
||||
static int sign(const T& a)
|
||||
{
|
||||
if (a < -SGLimits<T>::min())
|
||||
@@ -51,6 +56,37 @@ public:
|
||||
static T deg2rad(const T& val)
|
||||
{ return val*pi()/180; }
|
||||
|
||||
// normalize the value to be in a range between [min, max[
|
||||
static T
|
||||
normalizePeriodic(const T& min, const T& max, const T& value)
|
||||
{
|
||||
T range = max - min;
|
||||
if (range < SGLimits<T>::min())
|
||||
return min;
|
||||
T normalized = value - range*floor((value - min)/range);
|
||||
// two security checks that can only happen due to roundoff
|
||||
if (value <= min)
|
||||
return min;
|
||||
if (max <= normalized)
|
||||
return min;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// normalize the angle to be in a range between [-pi, pi[
|
||||
static T
|
||||
normalizeAngle(const T& angle)
|
||||
{ return normalizePeriodic(-pi(), pi(), angle); }
|
||||
|
||||
// normalize the angle to be in a range between [0, 2pi[
|
||||
static T
|
||||
normalizeAngle2(const T& angle)
|
||||
{ return normalizePeriodic(0, twopi(), angle); }
|
||||
|
||||
static T round(const T& v)
|
||||
{ return floor(v + T(0.5)); }
|
||||
static int roundToInt(const T& v)
|
||||
{ return int(round(v)); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// Returns true if v is a NaN value
|
||||
/// Use with care: allways code that you do not need to use that!
|
||||
@@ -71,7 +107,4 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef SGMisc<float> SGMiscf;
|
||||
typedef SGMisc<double> SGMiscd;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGPlane_H
|
||||
#define SGPlane_H
|
||||
|
||||
template<typename T>
|
||||
class SGPlane {
|
||||
public:
|
||||
SGPlane()
|
||||
{ }
|
||||
SGPlane(const SGVec3<T>& normal, T dist) :
|
||||
_normal(normal), _dist(dist)
|
||||
{ }
|
||||
SGPlane(const SGVec3<T> vertices[3]) :
|
||||
_normal(normalize(cross(vertices[1] - vertices[0],
|
||||
vertices[2] - vertices[0]))),
|
||||
_dist(-dot(_normal, vertices[0]))
|
||||
{ }
|
||||
|
||||
void setNormal(const SGVec3<T>& normal)
|
||||
{ _normal = normal; }
|
||||
const SGVec3<T>& getNormal() const
|
||||
{ return _normal; }
|
||||
|
||||
void setDist(const T& dist)
|
||||
{ _dist = dist; }
|
||||
const T& getDist() const
|
||||
{ return _dist; }
|
||||
|
||||
/// That is the distance where we measure positive in direction of the normal
|
||||
T getPositiveDist() const
|
||||
{ return -_dist; }
|
||||
/// That is the distance where we measure positive in the oposite direction
|
||||
/// of the normal.
|
||||
const T& getNegativeDist() const
|
||||
{ return _dist; }
|
||||
|
||||
private:
|
||||
// That ordering is important because of one constructor
|
||||
SGVec3<T> _normal;
|
||||
T _dist;
|
||||
};
|
||||
|
||||
#endif
|
||||
+286
-62
@@ -18,9 +18,50 @@
|
||||
#ifndef SGQuat_H
|
||||
#define SGQuat_H
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#include <osg/Quat>
|
||||
|
||||
template<typename T>
|
||||
struct SGQuatStorage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[4]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[4]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[4];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGQuatStorage<double> : public osg::Quat {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[4]
|
||||
{ return osg::Quat::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[4]
|
||||
{ return osg::Quat::_v; }
|
||||
|
||||
const osg::Quat& osg() const
|
||||
{ return *this; }
|
||||
osg::Quat& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 3D Vector Class
|
||||
template<typename T>
|
||||
class SGQuat {
|
||||
class SGQuat : protected SGQuatStorage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
@@ -33,7 +74,7 @@ public:
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
_data[i] = SGLimits<T>::quiet_NaN();
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
@@ -42,11 +83,13 @@ public:
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 4 elements
|
||||
explicit SGQuat(const T* d)
|
||||
{ _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; }
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGQuat(const osg::Quat& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
|
||||
/// Return a unit quaternion
|
||||
static SGQuat unit(void)
|
||||
{ return fromRealImag(1, SGVec3<T>(0)); }
|
||||
{ return fromRealImag(1, SGVec3<T>(0, 0, 0)); }
|
||||
|
||||
/// Return a quaternion from euler angles
|
||||
static SGQuat fromEulerRad(T z, T y, T x)
|
||||
@@ -87,13 +130,17 @@ public:
|
||||
static SGQuat fromHeadAttBankDeg(T h, T a, T b)
|
||||
{ return fromEulerDeg(h, a, b); }
|
||||
|
||||
/// Return a quaternion rotation the the horizontal local frame from given
|
||||
/// longitude and latitude
|
||||
/// Return a quaternion rotation from the earth centered to the
|
||||
/// simulation usual horizontal local frame from given
|
||||
/// longitude and latitude.
|
||||
/// The horizontal local frame used in simulations is the frame with x-axis
|
||||
/// pointing north, the y-axis pointing eastwards and the z axis
|
||||
/// pointing downwards.
|
||||
static SGQuat fromLonLatRad(T lon, T lat)
|
||||
{
|
||||
SGQuat q;
|
||||
T zd2 = T(0.5)*lon;
|
||||
T yd2 = T(-0.25)*SGMisc<value_type>::pi() - T(0.5)*lat;
|
||||
T yd2 = T(-0.25)*SGMisc<T>::pi() - T(0.5)*lat;
|
||||
T Szd2 = sin(zd2);
|
||||
T Syd2 = sin(yd2);
|
||||
T Czd2 = cos(zd2);
|
||||
@@ -104,11 +151,50 @@ public:
|
||||
q.z() = Szd2*Cyd2;
|
||||
return q;
|
||||
}
|
||||
|
||||
/// Return a quaternion rotation the the horizontal local frame from given
|
||||
/// longitude and latitude
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat fromLonLatDeg(T lon, T lat)
|
||||
{ return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat fromLonLat(const SGGeod& geod)
|
||||
{ return fromLonLatRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
|
||||
|
||||
/// Return a quaternion rotation from the earth centered to the
|
||||
/// OpenGL/viewer horizontal local frame from given longitude and latitude.
|
||||
/// This frame matches the usual OpenGL axis directions. That is the target
|
||||
/// frame has an x-axis pointing eastwards, y-axis pointing up and y z-axis
|
||||
/// pointing south.
|
||||
static SGQuat viewHLRad(T lon, T lat)
|
||||
{
|
||||
// That bails down to a 3-2-1 euler sequence lon+pi/2, 0, -lat-pi
|
||||
// what is here is again the hand optimized version ...
|
||||
SGQuat q;
|
||||
T xd2 = -T(0.5)*lat - T(0.5)*SGMisc<T>::pi();
|
||||
T zd2 = T(0.5)*lon + T(0.25)*SGMisc<T>::pi();
|
||||
T Szd2 = sin(zd2);
|
||||
T Sxd2 = sin(xd2);
|
||||
T Czd2 = cos(zd2);
|
||||
T Cxd2 = cos(xd2);
|
||||
q.w() = Cxd2*Czd2;
|
||||
q.x() = Sxd2*Czd2;
|
||||
q.y() = Sxd2*Szd2;
|
||||
q.z() = Cxd2*Szd2;
|
||||
return q;
|
||||
}
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat viewHLDeg(T lon, T lat)
|
||||
{ return viewHLRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(lat)); }
|
||||
/// Like the above provided for convenience
|
||||
static SGQuat viewHL(const SGGeod& geod)
|
||||
{ return viewHLRad(geod.getLongitudeRad(), geod.getLatitudeRad()); }
|
||||
|
||||
/// Convert a quaternion rotation from the simulation frame
|
||||
/// to the view (OpenGL) frame. That is it just swaps the axis part of
|
||||
/// this current quaternion.
|
||||
/// That proves useful when you want to use the euler 3-2-1 sequence
|
||||
/// for the usual heading/pitch/roll sequence within the context of
|
||||
/// OpenGL/viewer frames.
|
||||
static SGQuat simToView(const SGQuat& q)
|
||||
{ return SGQuat(q.y(), -q.z(), -q.x(), q.w()); }
|
||||
|
||||
/// Create a quaternion from the angle axis representation
|
||||
static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
|
||||
@@ -132,14 +218,100 @@ public:
|
||||
return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis);
|
||||
}
|
||||
|
||||
static SGQuat fromRotateTo(const SGVec3<T>& from, const SGVec3<T>& to)
|
||||
{
|
||||
T nfrom = norm(from);
|
||||
T nto = norm(to);
|
||||
if (nfrom < SGLimits<T>::min() || nto < SGLimits<T>::min())
|
||||
return SGQuat::unit();
|
||||
|
||||
return SGQuat::fromRotateToNorm((1/nfrom)*from, (1/nto)*to);
|
||||
}
|
||||
|
||||
// FIXME more finegrained error behavour.
|
||||
static SGQuat fromRotateTo(const SGVec3<T>& v1, unsigned i1,
|
||||
const SGVec3<T>& v2, unsigned i2)
|
||||
{
|
||||
T nrmv1 = norm(v1);
|
||||
T nrmv2 = norm(v2);
|
||||
if (nrmv1 < SGLimits<T>::min() || nrmv2 < SGLimits<T>::min())
|
||||
return SGQuat::unit();
|
||||
|
||||
SGVec3<T> nv1 = (1/nrmv1)*v1;
|
||||
SGVec3<T> nv2 = (1/nrmv2)*v2;
|
||||
T dv1v2 = dot(nv1, nv2);
|
||||
if (fabs(fabs(dv1v2)-1) < SGLimits<T>::epsilon())
|
||||
return SGQuat::unit();
|
||||
|
||||
// The target vector for the first rotation
|
||||
SGVec3<T> nto1 = SGVec3<T>::zeros();
|
||||
SGVec3<T> nto2 = SGVec3<T>::zeros();
|
||||
nto1[i1] = 1;
|
||||
nto2[i2] = 1;
|
||||
|
||||
// The first rotation can be done with the usual routine.
|
||||
SGQuat q = SGQuat::fromRotateToNorm(nv1, nto1);
|
||||
|
||||
// The rotation axis for the second rotation is the
|
||||
// target for the first one, so the rotation axis is nto1
|
||||
// We need to get the angle.
|
||||
|
||||
// Make nv2 exactly orthogonal to nv1.
|
||||
nv2 = normalize(nv2 - dv1v2*nv1);
|
||||
|
||||
SGVec3<T> tnv2 = q.transform(nv2);
|
||||
T cosang = dot(nto2, tnv2);
|
||||
T cos05ang = T(0.5+0.5*cosang);
|
||||
if (cos05ang <= 0)
|
||||
cosang = T(0);
|
||||
cos05ang = sqrt(cos05ang);
|
||||
T sig = dot(nto1, cross(nto2, tnv2));
|
||||
T sin05ang = T(0.5-0.5*cosang);
|
||||
if (sin05ang <= 0)
|
||||
sin05ang = 0;
|
||||
sin05ang = copysign(sqrt(sin05ang), sig);
|
||||
q *= SGQuat::fromRealImag(cos05ang, sin05ang*nto1);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
// Return a quaternion which rotates the vector given by v
|
||||
// to the vector -v. Other directions are *not* preserved.
|
||||
static SGQuat fromChangeSign(const SGVec3<T>& v)
|
||||
{
|
||||
// The vector from points to the oposite direction than to.
|
||||
// Find a vector perpendicular to the vector to.
|
||||
T absv1 = fabs(v(0));
|
||||
T absv2 = fabs(v(1));
|
||||
T absv3 = fabs(v(2));
|
||||
|
||||
SGVec3<T> axis;
|
||||
if (absv2 < absv1 && absv3 < absv1) {
|
||||
T quot = v(1)/v(0);
|
||||
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
|
||||
} else if (absv1 < absv2 && absv3 < absv2) {
|
||||
T quot = v(2)/v(1);
|
||||
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
|
||||
} else if (absv1 < absv3 && absv2 < absv3) {
|
||||
T quot = v(0)/v(2);
|
||||
axis = (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
|
||||
} else {
|
||||
// The all zero case.
|
||||
return SGQuat::unit();
|
||||
}
|
||||
|
||||
return SGQuat::fromRealImag(0, axis);
|
||||
}
|
||||
|
||||
/// Return a quaternion from real and imaginary part
|
||||
static SGQuat fromRealImag(T r, const SGVec3<T>& i)
|
||||
{
|
||||
SGQuat q;
|
||||
q.w() = r;
|
||||
q.x() = i(0);
|
||||
q.y() = i(1);
|
||||
q.z() = i(2);
|
||||
q.x() = i.x();
|
||||
q.y() = i.y();
|
||||
q.z() = i.z();
|
||||
return q;
|
||||
}
|
||||
|
||||
@@ -150,36 +322,36 @@ public:
|
||||
/// write the euler angles into the references
|
||||
void getEulerRad(T& zRad, T& yRad, T& xRad) const
|
||||
{
|
||||
value_type sqrQW = w()*w();
|
||||
value_type sqrQX = x()*x();
|
||||
value_type sqrQY = y()*y();
|
||||
value_type sqrQZ = z()*z();
|
||||
T sqrQW = w()*w();
|
||||
T sqrQX = x()*x();
|
||||
T sqrQY = y()*y();
|
||||
T sqrQZ = z()*z();
|
||||
|
||||
value_type num = 2*(y()*z() + w()*x());
|
||||
value_type den = sqrQW - sqrQX - sqrQY + sqrQZ;
|
||||
if (fabs(den) < SGLimits<value_type>::min() &&
|
||||
fabs(num) < SGLimits<value_type>::min())
|
||||
T num = 2*(y()*z() + w()*x());
|
||||
T den = sqrQW - sqrQX - sqrQY + sqrQZ;
|
||||
if (fabs(den) < SGLimits<T>::min() &&
|
||||
fabs(num) < SGLimits<T>::min())
|
||||
xRad = 0;
|
||||
else
|
||||
xRad = atan2(num, den);
|
||||
|
||||
value_type tmp = 2*(x()*z() - w()*y());
|
||||
T tmp = 2*(x()*z() - w()*y());
|
||||
if (tmp < -1)
|
||||
yRad = 0.5*SGMisc<value_type>::pi();
|
||||
yRad = 0.5*SGMisc<T>::pi();
|
||||
else if (1 < tmp)
|
||||
yRad = -0.5*SGMisc<value_type>::pi();
|
||||
yRad = -0.5*SGMisc<T>::pi();
|
||||
else
|
||||
yRad = -asin(tmp);
|
||||
|
||||
num = 2*(x()*y() + w()*z());
|
||||
den = sqrQW + sqrQX - sqrQY - sqrQZ;
|
||||
if (fabs(den) < SGLimits<value_type>::min() &&
|
||||
fabs(num) < SGLimits<value_type>::min())
|
||||
if (fabs(den) < SGLimits<T>::min() &&
|
||||
fabs(num) < SGLimits<T>::min())
|
||||
zRad = 0;
|
||||
else {
|
||||
value_type psi = atan2(num, den);
|
||||
T psi = atan2(num, den);
|
||||
if (psi < 0)
|
||||
psi += 2*SGMisc<value_type>::pi();
|
||||
psi += 2*SGMisc<T>::pi();
|
||||
zRad = psi;
|
||||
}
|
||||
}
|
||||
@@ -222,67 +394,66 @@ public:
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the z component
|
||||
const T& z(void) const
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the z component
|
||||
T& z(void)
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the w component
|
||||
const T& w(void) const
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
/// Access the w component
|
||||
T& w(void)
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
const T* data(void) const
|
||||
{ return _data; }
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
T* data(void)
|
||||
{ return _data; }
|
||||
/// Get the data pointer
|
||||
using SGQuatStorage<T>::data;
|
||||
|
||||
/// Readonly interface function to ssg's sgQuat/sgdQuat
|
||||
const T (&sg(void) const)[4]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgQuat/sgdQuat
|
||||
T (&sg(void))[4]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Quat*
|
||||
using SGQuatStorage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGQuat& operator+=(const SGQuat& v)
|
||||
{ _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; }
|
||||
{ data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
|
||||
/// Inplace subtraction
|
||||
SGQuat& operator-=(const SGQuat& v)
|
||||
{ _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; }
|
||||
{ data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGQuat& operator*=(S s)
|
||||
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; }
|
||||
{ data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGQuat& operator/=(S s)
|
||||
@@ -294,18 +465,18 @@ public:
|
||||
/// frame rotated with the quaternion
|
||||
SGVec3<T> transform(const SGVec3<T>& v) const
|
||||
{
|
||||
value_type r = 2/dot(*this, *this);
|
||||
T r = 2/dot(*this, *this);
|
||||
SGVec3<T> qimag = imag(*this);
|
||||
value_type qr = real(*this);
|
||||
T qr = real(*this);
|
||||
return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag - (r*qr)*cross(qimag, v);
|
||||
}
|
||||
/// Transform a vector from the coordinate frame rotated with the quaternion
|
||||
/// to the current coordinate frame
|
||||
SGVec3<T> backTransform(const SGVec3<T>& v) const
|
||||
{
|
||||
value_type r = 2/dot(*this, *this);
|
||||
T r = 2/dot(*this, *this);
|
||||
SGVec3<T> qimag = imag(*this);
|
||||
value_type qr = real(*this);
|
||||
T qr = real(*this);
|
||||
return (r*qr*qr - 1)*v + (r*dot(qimag, v))*qimag + (r*qr)*cross(qimag, v);
|
||||
}
|
||||
|
||||
@@ -318,7 +489,7 @@ public:
|
||||
|
||||
/// Return the time derivative of the quaternion given the angular velocity
|
||||
SGQuat
|
||||
derivative(const SGVec3<T>& angVel)
|
||||
derivative(const SGVec3<T>& angVel) const
|
||||
{
|
||||
SGQuat deriv;
|
||||
|
||||
@@ -331,8 +502,65 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/// The actual data
|
||||
T _data[4];
|
||||
|
||||
// Private because it assumes normalized inputs.
|
||||
static SGQuat
|
||||
fromRotateToSmaller90Deg(T cosang,
|
||||
const SGVec3<T>& from, const SGVec3<T>& to)
|
||||
{
|
||||
// In this function we assume that the angle required to rotate from
|
||||
// the vector from to the vector to is <= 90 deg.
|
||||
// That is done so because of possible instabilities when we rotate more
|
||||
// then 90deg.
|
||||
|
||||
// Note that the next comment does actually cover a *more* *general* case
|
||||
// than we need in this function. That shows that this formula is even
|
||||
// valid for rotations up to 180deg.
|
||||
|
||||
// Because of the signs in the axis, it is sufficient to care for angles
|
||||
// in the interval [-pi,pi]. That means that 0.5*angle is in the interval
|
||||
// [-pi/2,pi/2]. But in that range the cosine is allways >= 0.
|
||||
// So we do not need to care for egative roots in the following equation:
|
||||
T cos05ang = sqrt(0.5+0.5*cosang);
|
||||
|
||||
|
||||
// Now our assumption of angles <= 90 deg comes in play.
|
||||
// For that reason, we know that cos05ang is not zero.
|
||||
// It is even more, we can see from the above formula that
|
||||
// sqrt(0.5) < cos05ang.
|
||||
|
||||
|
||||
// Compute the rotation axis, that is
|
||||
// sin(angle)*normalized rotation axis
|
||||
SGVec3<T> axis = cross(to, from);
|
||||
|
||||
// We need sin(0.5*angle)*normalized rotation axis.
|
||||
// So rescale with sin(0.5*x)/sin(x).
|
||||
// To do that we use the equation:
|
||||
// sin(x) = 2*sin(0.5*x)*cos(0.5*x)
|
||||
return SGQuat::fromRealImag( cos05ang, (1/(2*cos05ang))*axis);
|
||||
}
|
||||
|
||||
// Private because it assumes normalized inputs.
|
||||
static SGQuat
|
||||
fromRotateToNorm(const SGVec3<T>& from, const SGVec3<T>& to)
|
||||
{
|
||||
// To avoid instabilities with roundoff, we distinguish between rotations
|
||||
// with more then 90deg and rotations with less than 90deg.
|
||||
|
||||
// Compute the cosine of the angle.
|
||||
T cosang = dot(from, to);
|
||||
|
||||
// For the small ones do direct computation
|
||||
if (T(-0.5) < cosang)
|
||||
return SGQuat::fromRotateToSmaller90Deg(cosang, from, to);
|
||||
|
||||
// For larger rotations. first rotate from to -from.
|
||||
// Past that we will have a smaller angle again.
|
||||
SGQuat q1 = SGQuat::fromChangeSign(from);
|
||||
SGQuat q2 = SGQuat::fromRotateToSmaller90Deg(-cosang, -from, to);
|
||||
return q1*q2;
|
||||
}
|
||||
};
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
@@ -552,10 +780,6 @@ std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGQuat<T>& v)
|
||||
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
|
||||
|
||||
/// Two classes doing actually the same on different types
|
||||
typedef SGQuat<float> SGQuatf;
|
||||
typedef SGQuat<double> SGQuatd;
|
||||
|
||||
inline
|
||||
SGQuatf
|
||||
toQuatf(const SGQuatd& v)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGRay_H
|
||||
#define SGRay_H
|
||||
|
||||
template<typename T>
|
||||
class SGRay {
|
||||
public:
|
||||
SGRay()
|
||||
{ }
|
||||
SGRay(const SGVec3<T>& origin, const SGVec3<T>& dir) :
|
||||
_origin(origin), _direction(dir)
|
||||
{ }
|
||||
|
||||
void set(const SGVec3<T>& origin, const SGVec3<T>& dir)
|
||||
{ _origin = origin; _direction = dir; }
|
||||
|
||||
void setOrigin(const SGVec3<T>& origin)
|
||||
{ _origin = origin; }
|
||||
const SGVec3<T>& getOrigin() const
|
||||
{ return _origin; }
|
||||
|
||||
void setDirection(const SGVec3<T>& direction)
|
||||
{ _direction = direction; }
|
||||
const SGVec3<T>& getDirection() const
|
||||
{ return _direction; }
|
||||
|
||||
SGVec3<T> getNormalizedDirection() const
|
||||
{ return normalize(getDirection()); }
|
||||
|
||||
private:
|
||||
SGVec3<T> _origin;
|
||||
SGVec3<T> _direction;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGRay<T>& ray)
|
||||
{
|
||||
return s << "ray: origin = " << ray.getOrigin()
|
||||
<< ", direction = " << ray.getDirection();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGSphere_H
|
||||
#define SGSphere_H
|
||||
|
||||
template<typename T>
|
||||
class SGSphere {
|
||||
public:
|
||||
SGSphere() :
|
||||
_radius(-1)
|
||||
{ }
|
||||
SGSphere(const SGVec3<T>& center, const T& radius) :
|
||||
_center(center),
|
||||
_radius(radius)
|
||||
{ }
|
||||
|
||||
const SGVec3<T>& getCenter() const
|
||||
{ return _center; }
|
||||
void setCenter(const SGVec3<T>& center)
|
||||
{ _center = center; }
|
||||
|
||||
const T& getRadius() const
|
||||
{ return _radius; }
|
||||
void setRadius(const T& radius)
|
||||
{ _radius = radius; }
|
||||
T getRadius2() const
|
||||
{ return _radius*_radius; }
|
||||
|
||||
const bool empty() const
|
||||
{ return !valid(); }
|
||||
|
||||
bool valid() const
|
||||
{ return 0 <= _radius; }
|
||||
|
||||
void clear()
|
||||
{ _radius = -1; }
|
||||
|
||||
void expandBy(const SGVec3<T>& v)
|
||||
{
|
||||
if (empty()) {
|
||||
_center = v;
|
||||
_radius = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
T dist2 = distSqr(_center, v);
|
||||
if (dist2 <= getRadius2())
|
||||
return;
|
||||
|
||||
T dist = sqrt(dist2);
|
||||
T newRadius = T(0.5)*(_radius + dist);
|
||||
_center += ((newRadius - _radius)/dist)*(v - _center);
|
||||
_radius = newRadius;
|
||||
}
|
||||
|
||||
private:
|
||||
SGVec3<T> _center;
|
||||
T _radius;
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGSphere<T>& sphere)
|
||||
{
|
||||
return s << "center = " << sphere.getCenter()
|
||||
<< ", radius = " << sphere.getRadius();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGTriangle_H
|
||||
#define SGTrianlge_H
|
||||
|
||||
template<typename T>
|
||||
class SGTriangle {
|
||||
public:
|
||||
SGTriangle()
|
||||
{ }
|
||||
SGTriangle(const SGVec3<T>& v0, const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ set(v0, v1, v2); }
|
||||
SGTriangle(const SGVec3<T> v[3])
|
||||
{ set(v); }
|
||||
|
||||
void set(const SGVec3<T>& v0, const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
_v0 = v0;
|
||||
_d[0] = v1 - v0;
|
||||
_d[1] = v2 - v0;
|
||||
}
|
||||
void set(const SGVec3<T> v[3])
|
||||
{
|
||||
_v0 = v[0];
|
||||
_d[0] = v[1] - v[0];
|
||||
_d[1] = v[2] - v[0];
|
||||
}
|
||||
|
||||
SGVec3d getCenter() const
|
||||
{
|
||||
SGBoxd box;
|
||||
box.expandBy(_v0);
|
||||
box.expandBy(_v0 + _d[0]);
|
||||
box.expandBy(_v0 + _d[1]);
|
||||
return box.getCenter();
|
||||
}
|
||||
|
||||
// note that the index is unchecked
|
||||
SGVec3<T> getVertex(unsigned i) const
|
||||
{
|
||||
if (0 < i)
|
||||
return _v0 + _d[i-1];
|
||||
return _v0;
|
||||
}
|
||||
/// return the normalized surface normal
|
||||
SGVec3<T> getNormal() const
|
||||
{ return normalize(cross(_d[0], _d[1])); }
|
||||
|
||||
const SGVec3<T>& getBaseVertex() const
|
||||
{ return _v0; }
|
||||
void setBaseVertex(const SGVec3<T>& v)
|
||||
{ _v0 = v; }
|
||||
const SGVec3<T>& getEdge(unsigned i) const
|
||||
{ return _d[i]; }
|
||||
void setEdge(unsigned i, const SGVec3<T>& d)
|
||||
{ _d[i] = d; }
|
||||
|
||||
// flip the positive side
|
||||
void flip()
|
||||
{
|
||||
SGVec3<T> tmp = _d[0];
|
||||
_d[0] = _d[1];
|
||||
_d[1] = tmp;
|
||||
}
|
||||
private:
|
||||
/// Store one vertex directly, _d is the offset of the other two
|
||||
/// vertices wrt the base vertex
|
||||
/// For fast intersection tests this format prooves usefull. For that same
|
||||
/// purpose also cache the cross product of the _d[i].
|
||||
SGVec3<T> _v0;
|
||||
SGVec3<T> _d[2];
|
||||
};
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s,
|
||||
const SGTriangle<T>& triangle)
|
||||
{
|
||||
return s << "triangle: v0 = " << triangle.getVertex(0)
|
||||
<< ", v1 = " << triangle.getVertex(1)
|
||||
<< ", v2 = " << triangle.getVertex(2);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,405 @@
|
||||
// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 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
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SGVec2_H
|
||||
#define SGVec2_H
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec2d>
|
||||
|
||||
template<typename T>
|
||||
struct SGVec2Storage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[2]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[2]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[2];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec2Storage<float> : public osg::Vec2f {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const float (&data(void) const)[2]
|
||||
{ return osg::Vec2f::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
float (&data(void))[2]
|
||||
{ return osg::Vec2f::_v; }
|
||||
|
||||
const osg::Vec2f& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec2f& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec2Storage<double> : public osg::Vec2d {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[2]
|
||||
{ return osg::Vec2d::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[2]
|
||||
{ return osg::Vec2d::_v; }
|
||||
|
||||
const osg::Vec2d& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec2d& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 2D Vector Class
|
||||
template<typename T>
|
||||
class SGVec2 : protected SGVec2Storage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
/// Default constructor. Does not initialize at all.
|
||||
/// If you need them zero initialized, use SGVec2::zeros()
|
||||
SGVec2(void)
|
||||
{
|
||||
/// Initialize with nans in the debug build, that will guarantee to have
|
||||
/// a fast uninitialized default constructor in the release but shows up
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 2; ++i)
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
SGVec2(T x, T y)
|
||||
{ data()[0] = x; data()[1] = y; }
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 2 elements
|
||||
explicit SGVec2(const T* d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; }
|
||||
explicit SGVec2(const osg::Vec2f& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; }
|
||||
explicit SGVec2(const osg::Vec2d& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; }
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return data()[1]; }
|
||||
|
||||
/// Get the data pointer
|
||||
using SGVec2Storage<T>::data;
|
||||
|
||||
/// Readonly interface function to ssg's sgVec2/sgdVec2
|
||||
const T (&sg(void) const)[2]
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgVec2/sgdVec2
|
||||
T (&sg(void))[2]
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Vec2*
|
||||
using SGVec2Storage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGVec2& operator+=(const SGVec2& v)
|
||||
{ data()[0] += v(0); data()[1] += v(1); return *this; }
|
||||
/// Inplace subtraction
|
||||
SGVec2& operator-=(const SGVec2& v)
|
||||
{ data()[0] -= v(0); data()[1] -= v(1); return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGVec2& operator*=(S s)
|
||||
{ data()[0] *= s; data()[1] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGVec2& operator/=(S s)
|
||||
{ return operator*=(1/T(s)); }
|
||||
|
||||
/// Return an all zero vector
|
||||
static SGVec2 zeros(void)
|
||||
{ return SGVec2(0, 0); }
|
||||
/// Return unit vectors
|
||||
static SGVec2 e1(void)
|
||||
{ return SGVec2(1, 0); }
|
||||
static SGVec2 e2(void)
|
||||
{ return SGVec2(0, 1); }
|
||||
};
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
template<typename T>
|
||||
inline
|
||||
const SGVec2<T>&
|
||||
operator+(const SGVec2<T>& v)
|
||||
{ return v; }
|
||||
|
||||
/// Unary -, do nearly nothing
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator-(const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(-v(0), -v(1)); }
|
||||
|
||||
/// Binary +
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator+(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return SGVec2<T>(v1(0)+v2(0), v1(1)+v2(1)); }
|
||||
|
||||
/// Binary -
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator-(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return SGVec2<T>(v1(0)-v2(0), v1(1)-v2(1)); }
|
||||
|
||||
/// Scalar multiplication
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator*(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(s*v(0), s*v(1)); }
|
||||
|
||||
/// Scalar multiplication
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
operator*(const SGVec2<T>& v, S s)
|
||||
{ return SGVec2<T>(s*v(0), s*v(1)); }
|
||||
|
||||
/// multiplication as a multiplicator, that is assume that the first vector
|
||||
/// represents a 2x2 diagonal matrix with the diagonal elements in the vector.
|
||||
/// Then the result is the product of that matrix times the second vector.
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
mult(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return SGVec2<T>(v1(0)*v2(0), v1(1)*v2(1)); }
|
||||
|
||||
/// component wise min
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
min(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{return SGVec2<T>(SGMisc<T>::min(v1(0), v2(0)), SGMisc<T>::min(v1(1), v2(1)));}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
min(const SGVec2<T>& v, S s)
|
||||
{ return SGVec2<T>(SGMisc<T>::min(s, v(0)), SGMisc<T>::min(s, v(1))); }
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
min(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(SGMisc<T>::min(s, v(0)), SGMisc<T>::min(s, v(1))); }
|
||||
|
||||
/// component wise max
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
max(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{return SGVec2<T>(SGMisc<T>::max(v1(0), v2(0)), SGMisc<T>::max(v1(1), v2(1)));}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
max(const SGVec2<T>& v, S s)
|
||||
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
max(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
dot(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return v1(0)*v2(0) + v1(1)*v2(1); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
norm(const SGVec2<T>& v)
|
||||
{ return sqrt(dot(v, v)); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
length(const SGVec2<T>& v)
|
||||
{ return sqrt(dot(v, v)); }
|
||||
|
||||
/// The 1-norm of the vector, this one is the fastest length function we
|
||||
/// can implement on modern cpu's
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
norm1(const SGVec2<T>& v)
|
||||
{ return fabs(v(0)) + fabs(v(1)); }
|
||||
|
||||
/// The inf-norm of the vector
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
normI(const SGVec2<T>& v)
|
||||
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1))); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec2<T>
|
||||
normalize(const SGVec2<T>& v)
|
||||
{ return (1/norm(v))*v; }
|
||||
|
||||
/// Return true if exactly the same
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator==(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return v1(0) == v2(0) && v1(1) == v2(1); }
|
||||
|
||||
/// Return true if not exactly the same
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator!=(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return ! (v1 == v2); }
|
||||
|
||||
/// Return true if smaller, good for putting that into a std::map
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else return (v1(1) < v2(1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<=(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else return (v1(1) <= v2(1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return operator<(v2, v1); }
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>=(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return operator<=(v2, v1); }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2, T rtol, T atol)
|
||||
{ return norm1(v1 - v2) < rtol*(norm1(v1) + norm1(v2)) + atol; }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2, T rtol)
|
||||
{ return norm1(v1 - v2) < rtol*(norm1(v1) + norm1(v2)); }
|
||||
|
||||
/// Return true if about equal to roundoff of the underlying type
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
equivalent(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{
|
||||
T tol = 100*SGLimits<T>::epsilon();
|
||||
return equivalent(v1, v2, tol, tol);
|
||||
}
|
||||
|
||||
/// The euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
dist(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ return norm(v1 - v2); }
|
||||
|
||||
/// The squared euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
distSqr(const SGVec2<T>& v1, const SGVec2<T>& v2)
|
||||
{ SGVec2<T> tmp = v1 - v2; return dot(tmp, tmp); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
isNaN(const SGVec2<T>& v)
|
||||
{
|
||||
return SGMisc<T>::isNaN(v(0)) || SGMisc<T>::isNaN(v(1));
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Output to an ostream
|
||||
template<typename char_type, typename traits_type, typename T>
|
||||
inline
|
||||
std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec2<T>& v)
|
||||
{ return s << "[ " << v(0) << ", " << v(1) << " ]"; }
|
||||
|
||||
inline
|
||||
SGVec2f
|
||||
toVec2f(const SGVec2d& v)
|
||||
{ return SGVec2f((float)v(0), (float)v(1)); }
|
||||
|
||||
inline
|
||||
SGVec2d
|
||||
toVec2d(const SGVec2f& v)
|
||||
{ return SGVec2d(v(0), v(1)); }
|
||||
|
||||
#endif
|
||||
+275
-40
@@ -18,9 +18,58 @@
|
||||
#ifndef SGVec3_H
|
||||
#define SGVec3_H
|
||||
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec3d>
|
||||
|
||||
template<typename T>
|
||||
struct SGVec3Storage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[3]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[3]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[3];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec3Storage<float> : public osg::Vec3f {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const float (&data(void) const)[3]
|
||||
{ return osg::Vec3f::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
float (&data(void))[3]
|
||||
{ return osg::Vec3f::_v; }
|
||||
|
||||
const osg::Vec3f& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec3f& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec3Storage<double> : public osg::Vec3d {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[3]
|
||||
{ return osg::Vec3d::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[3]
|
||||
{ return osg::Vec3d::_v; }
|
||||
|
||||
const osg::Vec3d& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec3d& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 3D Vector Class
|
||||
template<typename T>
|
||||
class SGVec3 {
|
||||
class SGVec3 : protected SGVec3Storage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
@@ -33,82 +82,79 @@ public:
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
_data[i] = SGLimits<T>::quiet_NaN();
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
SGVec3(T x, T y, T z)
|
||||
{ _data[0] = x; _data[1] = y; _data[2] = z; }
|
||||
{ data()[0] = x; data()[1] = y; data()[2] = z; }
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 3 elements
|
||||
explicit SGVec3(const T* data)
|
||||
{ _data[0] = data[0]; _data[1] = data[1]; _data[2] = data[2]; }
|
||||
/// Constructor. Initialize by a geodetic coordinate
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
SGVec3(const SGGeod& geod)
|
||||
{ SGGeodesy::SGGeodToCart(geod, *this); }
|
||||
/// Constructor. Initialize by a geocentric coordinate
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
SGVec3(const SGGeoc& geoc)
|
||||
{ SGGeodesy::SGGeocToCart(geoc, *this); }
|
||||
explicit SGVec3(const T* d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||
explicit SGVec3(const osg::Vec3f& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||
explicit SGVec3(const osg::Vec3d& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||
explicit SGVec3(const SGVec2<T>& v2, const T& v3 = 0)
|
||||
{ data()[0] = v2[0]; data()[1] = v2[1]; data()[2] = v3; }
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the z component
|
||||
const T& z(void) const
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the z component
|
||||
T& z(void)
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
|
||||
/// Get the data pointer
|
||||
const T* data(void) const
|
||||
{ return _data; }
|
||||
/// Get the data pointer
|
||||
T* data(void)
|
||||
{ return _data; }
|
||||
using SGVec3Storage<T>::data;
|
||||
|
||||
/// Readonly interface function to ssg's sgVec3/sgdVec3
|
||||
const T (&sg(void) const)[3]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgVec3/sgdVec3
|
||||
T (&sg(void))[3]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Vec3*
|
||||
using SGVec3Storage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGVec3& operator+=(const SGVec3& v)
|
||||
{ _data[0] += v(0); _data[1] += v(1); _data[2] += v(2); return *this; }
|
||||
{ data()[0] += v(0); data()[1] += v(1); data()[2] += v(2); return *this; }
|
||||
/// Inplace subtraction
|
||||
SGVec3& operator-=(const SGVec3& v)
|
||||
{ _data[0] -= v(0); _data[1] -= v(1); _data[2] -= v(2); return *this; }
|
||||
{ data()[0] -= v(0); data()[1] -= v(1); data()[2] -= v(2); return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGVec3& operator*=(S s)
|
||||
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; return *this; }
|
||||
{ data()[0] *= s; data()[1] *= s; data()[2] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGVec3& operator/=(S s)
|
||||
@@ -125,11 +171,54 @@ public:
|
||||
static SGVec3 e3(void)
|
||||
{ return SGVec3(0, 0, 1); }
|
||||
|
||||
private:
|
||||
/// The actual data
|
||||
T _data[3];
|
||||
/// Constructor. Initialize by a geodetic coordinate
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGVec3 fromGeod(const SGGeod& geod);
|
||||
/// Constructor. Initialize by a geocentric coordinate
|
||||
/// Note that this conversion is relatively expensive to compute
|
||||
static SGVec3 fromGeoc(const SGGeoc& geoc);
|
||||
};
|
||||
|
||||
template<>
|
||||
inline
|
||||
SGVec3<double>
|
||||
SGVec3<double>::fromGeod(const SGGeod& geod)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeodToCart(geod, cart);
|
||||
return cart;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
SGVec3<float>
|
||||
SGVec3<float>::fromGeod(const SGGeod& geod)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeodToCart(geod, cart);
|
||||
return SGVec3<float>(cart(0), cart(1), cart(2));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
SGVec3<double>
|
||||
SGVec3<double>::fromGeoc(const SGGeoc& geoc)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeocToCart(geoc, cart);
|
||||
return cart;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
SGVec3<float>
|
||||
SGVec3<float>::fromGeoc(const SGGeoc& geoc)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeocToCart(geoc, cart);
|
||||
return SGVec3<float>(cart(0), cart(1), cart(2));
|
||||
}
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -172,6 +261,73 @@ SGVec3<T>
|
||||
operator*(const SGVec3<T>& v, S s)
|
||||
{ return SGVec3<T>(s*v(0), s*v(1), s*v(2)); }
|
||||
|
||||
/// multiplication as a multiplicator, that is assume that the first vector
|
||||
/// represents a 3x3 diagonal matrix with the diagonal elements in the vector.
|
||||
/// Then the result is the product of that matrix times the second vector.
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
mult(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return SGVec3<T>(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2)); }
|
||||
|
||||
/// component wise min
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
min(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::min(v1(0), v2(0)),
|
||||
SGMisc<T>::min(v1(1), v2(1)),
|
||||
SGMisc<T>::min(v1(2), v2(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
min(const SGVec3<T>& v, S s)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
min(S s, const SGVec3<T>& v)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)));
|
||||
}
|
||||
|
||||
/// component wise max
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
max(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::max(v1(0), v2(0)),
|
||||
SGMisc<T>::max(v1(1), v2(1)),
|
||||
SGMisc<T>::max(v1(2), v2(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
max(const SGVec3<T>& v, S s)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
max(S s, const SGVec3<T>& v)
|
||||
{
|
||||
return SGVec3<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)));
|
||||
}
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -201,6 +357,13 @@ T
|
||||
norm1(const SGVec3<T>& v)
|
||||
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)); }
|
||||
|
||||
/// The inf-norm of the vector
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
normI(const SGVec3<T>& v)
|
||||
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1)), fabs(v(2))); }
|
||||
|
||||
/// Vector cross product
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -212,6 +375,31 @@ cross(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
v1(0)*v2(1) - v1(1)*v2(0));
|
||||
}
|
||||
|
||||
/// return any normalized vector perpendicular to v
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec3<T>
|
||||
perpendicular(const SGVec3<T>& v)
|
||||
{
|
||||
T absv1 = fabs(v(0));
|
||||
T absv2 = fabs(v(1));
|
||||
T absv3 = fabs(v(2));
|
||||
|
||||
if (absv2 < absv1 && absv3 < absv1) {
|
||||
T quot = v(1)/v(0);
|
||||
return (1/sqrt(1+quot*quot))*SGVec3<T>(quot, -1, 0);
|
||||
} else if (absv3 < absv2) {
|
||||
T quot = v(2)/v(1);
|
||||
return (1/sqrt(1+quot*quot))*SGVec3<T>(0, quot, -1);
|
||||
} else if (SGLimits<T>::min() < absv3) {
|
||||
T quot = v(0)/v(2);
|
||||
return (1/sqrt(1+quot*quot))*SGVec3<T>(-1, 0, quot);
|
||||
} else {
|
||||
// the all zero case ...
|
||||
return SGVec3<T>(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -233,6 +421,43 @@ bool
|
||||
operator!=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return ! (v1 == v2); }
|
||||
|
||||
/// Return true if smaller, good for putting that into a std::map
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else return (v1(2) < v2(2));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else return (v1(2) <= v2(2));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return operator<(v2, v1); }
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return operator<=(v2, v1); }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -257,6 +482,20 @@ equivalent(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
return equivalent(v1, v2, tol, tol);
|
||||
}
|
||||
|
||||
/// The euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
dist(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ return norm(v1 - v2); }
|
||||
|
||||
/// The squared euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
distSqr(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||
{ SGVec3<T> tmp = v1 - v2; return dot(tmp, tmp); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -275,10 +514,6 @@ std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec3<T>& v)
|
||||
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << " ]"; }
|
||||
|
||||
/// Two classes doing actually the same on different types
|
||||
typedef SGVec3<float> SGVec3f;
|
||||
typedef SGVec3<double> SGVec3d;
|
||||
|
||||
inline
|
||||
SGVec3f
|
||||
toVec3f(const SGVec3d& v)
|
||||
|
||||
+218
-38
@@ -18,9 +18,58 @@
|
||||
#ifndef SGVec4_H
|
||||
#define SGVec4_H
|
||||
|
||||
#include <osg/Vec4f>
|
||||
#include <osg/Vec4d>
|
||||
|
||||
template<typename T>
|
||||
struct SGVec4Storage {
|
||||
/// Readonly raw storage interface
|
||||
const T (&data(void) const)[4]
|
||||
{ return _data; }
|
||||
/// Readonly raw storage interface
|
||||
T (&data(void))[4]
|
||||
{ return _data; }
|
||||
|
||||
void osg() const
|
||||
{ }
|
||||
|
||||
private:
|
||||
T _data[4];
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec4Storage<float> : public osg::Vec4f {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const float (&data(void) const)[4]
|
||||
{ return osg::Vec4f::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
float (&data(void))[4]
|
||||
{ return osg::Vec4f::_v; }
|
||||
|
||||
const osg::Vec4f& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec4f& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SGVec4Storage<double> : public osg::Vec4d {
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const double (&data(void) const)[4]
|
||||
{ return osg::Vec4d::_v; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
double (&data(void))[4]
|
||||
{ return osg::Vec4d::_v; }
|
||||
|
||||
const osg::Vec4d& osg() const
|
||||
{ return *this; }
|
||||
osg::Vec4d& osg()
|
||||
{ return *this; }
|
||||
};
|
||||
|
||||
/// 4D Vector Class
|
||||
template<typename T>
|
||||
class SGVec4 {
|
||||
class SGVec4 : protected SGVec4Storage<T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
@@ -33,82 +82,86 @@ public:
|
||||
/// uninitialized values in the debug build very fast ...
|
||||
#ifndef NDEBUG
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
_data[i] = SGLimits<T>::quiet_NaN();
|
||||
data()[i] = SGLimits<T>::quiet_NaN();
|
||||
#endif
|
||||
}
|
||||
/// Constructor. Initialize by the given values
|
||||
SGVec4(T x, T y, T z, T w)
|
||||
{ _data[0] = x; _data[1] = y; _data[2] = z; _data[3] = w; }
|
||||
{ data()[0] = x; data()[1] = y; data()[2] = z; data()[3] = w; }
|
||||
/// Constructor. Initialize by the content of a plain array,
|
||||
/// make sure it has at least 3 elements
|
||||
explicit SGVec4(const T* d)
|
||||
{ _data[0] = d[0]; _data[1] = d[1]; _data[2] = d[2]; _data[3] = d[3]; }
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGVec4(const osg::Vec4f& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGVec4(const osg::Vec4d& d)
|
||||
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; data()[3] = d[3]; }
|
||||
explicit SGVec4(const SGVec3<T>& v3, const T& v4 = 0)
|
||||
{ data()[0] = v3[0]; data()[1] = v3[1]; data()[2] = v3[2]; data()[3] = v4; }
|
||||
|
||||
|
||||
/// Access by index, the index is unchecked
|
||||
const T& operator()(unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access by index, the index is unchecked
|
||||
T& operator()(unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access raw data by index, the index is unchecked
|
||||
const T& operator[](unsigned i) const
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
/// Access raw data by index, the index is unchecked
|
||||
T& operator[](unsigned i)
|
||||
{ return _data[i]; }
|
||||
{ return data()[i]; }
|
||||
|
||||
/// Access the x component
|
||||
const T& x(void) const
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the x component
|
||||
T& x(void)
|
||||
{ return _data[0]; }
|
||||
{ return data()[0]; }
|
||||
/// Access the y component
|
||||
const T& y(void) const
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the y component
|
||||
T& y(void)
|
||||
{ return _data[1]; }
|
||||
{ return data()[1]; }
|
||||
/// Access the z component
|
||||
const T& z(void) const
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the z component
|
||||
T& z(void)
|
||||
{ return _data[2]; }
|
||||
{ return data()[2]; }
|
||||
/// Access the x component
|
||||
const T& w(void) const
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
/// Access the x component
|
||||
T& w(void)
|
||||
{ return _data[3]; }
|
||||
{ return data()[3]; }
|
||||
|
||||
/// Get the data pointer
|
||||
using SGVec4Storage<T>::data;
|
||||
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
const T* data(void) const
|
||||
{ return _data; }
|
||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
||||
T* data(void)
|
||||
{ return _data; }
|
||||
|
||||
/// Readonly interface function to ssg's sgVec3/sgdVec3
|
||||
/// Readonly interface function to ssg's sgVec4/sgdVec4
|
||||
const T (&sg(void) const)[4]
|
||||
{ return _data; }
|
||||
/// Interface function to ssg's sgVec3/sgdVec3
|
||||
{ return data(); }
|
||||
/// Interface function to ssg's sgVec4/sgdVec4
|
||||
T (&sg(void))[4]
|
||||
{ return _data; }
|
||||
{ return data(); }
|
||||
|
||||
/// Interface function to osg's Vec4*
|
||||
using SGVec4Storage<T>::osg;
|
||||
|
||||
/// Inplace addition
|
||||
SGVec4& operator+=(const SGVec4& v)
|
||||
{ _data[0]+=v(0);_data[1]+=v(1);_data[2]+=v(2);_data[3]+=v(3);return *this; }
|
||||
{ data()[0]+=v(0);data()[1]+=v(1);data()[2]+=v(2);data()[3]+=v(3);return *this; }
|
||||
/// Inplace subtraction
|
||||
SGVec4& operator-=(const SGVec4& v)
|
||||
{ _data[0]-=v(0);_data[1]-=v(1);_data[2]-=v(2);_data[3]-=v(3);return *this; }
|
||||
{ data()[0]-=v(0);data()[1]-=v(1);data()[2]-=v(2);data()[3]-=v(3);return *this; }
|
||||
/// Inplace scalar multiplication
|
||||
template<typename S>
|
||||
SGVec4& operator*=(S s)
|
||||
{ _data[0] *= s; _data[1] *= s; _data[2] *= s; _data[3] *= s; return *this; }
|
||||
{ data()[0] *= s; data()[1] *= s; data()[2] *= s; data()[3] *= s; return *this; }
|
||||
/// Inplace scalar multiplication by 1/s
|
||||
template<typename S>
|
||||
SGVec4& operator/=(S s)
|
||||
@@ -126,10 +179,6 @@ public:
|
||||
{ return SGVec4(0, 0, 1, 0); }
|
||||
static SGVec4 e4(void)
|
||||
{ return SGVec4(0, 0, 0, 1); }
|
||||
|
||||
private:
|
||||
/// The actual data
|
||||
T _data[4];
|
||||
};
|
||||
|
||||
/// Unary +, do nothing ...
|
||||
@@ -174,6 +223,79 @@ SGVec4<T>
|
||||
operator*(const SGVec4<T>& v, S s)
|
||||
{ return SGVec4<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
|
||||
|
||||
/// multiplication as a multiplicator, that is assume that the first vector
|
||||
/// represents a 4x4 diagonal matrix with the diagonal elements in the vector.
|
||||
/// Then the result is the product of that matrix times the second vector.
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
mult(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return SGVec4<T>(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2), v1(3)*v2(3)); }
|
||||
|
||||
/// component wise min
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
min(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::min(v1(0), v2(0)),
|
||||
SGMisc<T>::min(v1(1), v2(1)),
|
||||
SGMisc<T>::min(v1(2), v2(2)),
|
||||
SGMisc<T>::min(v1(3), v2(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
min(const SGVec4<T>& v, S s)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)),
|
||||
SGMisc<T>::min(s, v(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
min(S s, const SGVec4<T>& v)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::min(s, v(0)),
|
||||
SGMisc<T>::min(s, v(1)),
|
||||
SGMisc<T>::min(s, v(2)),
|
||||
SGMisc<T>::min(s, v(3)));
|
||||
}
|
||||
|
||||
/// component wise max
|
||||
template<typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
max(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::max(v1(0), v2(0)),
|
||||
SGMisc<T>::max(v1(1), v2(1)),
|
||||
SGMisc<T>::max(v1(2), v2(2)),
|
||||
SGMisc<T>::max(v1(3), v2(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
max(const SGVec4<T>& v, S s)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)),
|
||||
SGMisc<T>::max(s, v(3)));
|
||||
}
|
||||
template<typename S, typename T>
|
||||
inline
|
||||
SGVec4<T>
|
||||
max(S s, const SGVec4<T>& v)
|
||||
{
|
||||
return SGVec4<T>(SGMisc<T>::max(s, v(0)),
|
||||
SGMisc<T>::max(s, v(1)),
|
||||
SGMisc<T>::max(s, v(2)),
|
||||
SGMisc<T>::max(s, v(3)));
|
||||
}
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -203,6 +325,13 @@ T
|
||||
norm1(const SGVec4<T>& v)
|
||||
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); }
|
||||
|
||||
/// The inf-norm of the vector
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
normI(const SGVec4<T>& v)
|
||||
{ return SGMisc<T>::max(fabs(v(0)), fabs(v(1)), fabs(v(2)), fabs(v(2))); }
|
||||
|
||||
/// The euclidean norm of the vector, that is what most people call length
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -224,6 +353,47 @@ bool
|
||||
operator!=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return ! (v1 == v2); }
|
||||
|
||||
/// Return true if smaller, good for putting that into a std::map
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else if (v1(2) < v2(2)) return true;
|
||||
else if (v2(2) < v1(2)) return false;
|
||||
else return (v1(3) < v2(3));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator<=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{
|
||||
if (v1(0) < v2(0)) return true;
|
||||
else if (v2(0) < v1(0)) return false;
|
||||
else if (v1(1) < v2(1)) return true;
|
||||
else if (v2(1) < v1(1)) return false;
|
||||
else if (v1(2) < v2(2)) return true;
|
||||
else if (v2(2) < v1(2)) return false;
|
||||
else return (v1(3) <= v2(3));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return operator<(v2, v1); }
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
bool
|
||||
operator>=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return operator<=(v2, v1); }
|
||||
|
||||
/// Return true if equal to the relative tolerance tol
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -248,6 +418,20 @@ equivalent(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
return equivalent(v1, v2, tol, tol);
|
||||
}
|
||||
|
||||
/// The euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
dist(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ return norm(v1 - v2); }
|
||||
|
||||
/// The squared euclidean distance of the two vectors
|
||||
template<typename T>
|
||||
inline
|
||||
T
|
||||
distSqr(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||
{ SGVec4<T> tmp = v1 - v2; return dot(tmp, tmp); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename T>
|
||||
inline
|
||||
@@ -266,10 +450,6 @@ std::basic_ostream<char_type, traits_type>&
|
||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec4<T>& v)
|
||||
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
|
||||
|
||||
/// Two classes doing actually the same on different types
|
||||
typedef SGVec4<float> SGVec4f;
|
||||
typedef SGVec4<double> SGVec4d;
|
||||
|
||||
inline
|
||||
SGVec4f
|
||||
toVec4f(const SGVec4d& v)
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
/*
|
||||
* \file fastmath.cxx
|
||||
* fast mathematics routines.
|
||||
*
|
||||
* Refferences:
|
||||
*
|
||||
* A Fast, Compact Approximation of the Exponential Function
|
||||
* Nicol N. Schraudolph
|
||||
* IDSIA, Lugano, Switzerland
|
||||
* http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
|
||||
*
|
||||
* Base-2 exp, Laurent de Soras
|
||||
* http://www.musicdsp.org/archive.php?classid=5#106
|
||||
*
|
||||
* Fast log() Function, by Laurent de Soras:
|
||||
* http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-Fastlogfunction&forum=totd&id=-1
|
||||
*
|
||||
* Sin, Cos, Tan approximation
|
||||
* http://www.musicdsp.org/showArchiveComment.php?ArchiveID=115
|
||||
*
|
||||
* fast floating point power computation:
|
||||
* http://playstation2-linux.com/download/adam/power.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
#include <simgear/constants.h>
|
||||
|
||||
#include "fastmath.hxx"
|
||||
|
||||
/**
|
||||
* This function is on avarage 9 times faster than the system exp() function
|
||||
* and has an error of about 1.5%
|
||||
*/
|
||||
static union {
|
||||
double d;
|
||||
struct {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
int i, j;
|
||||
#else
|
||||
int j, i;
|
||||
#endif
|
||||
} n;
|
||||
} _eco;
|
||||
|
||||
double fast_exp(double val) {
|
||||
const double a = 1048576/M_LN2;
|
||||
const double b_c = 1072632447; /* 1072693248 - 60801 */
|
||||
|
||||
_eco.n.i = (int)(a*val + b_c);
|
||||
|
||||
return _eco.d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linear approx. between 2 integer values of val. Uses 32-bit integers.
|
||||
* Not very efficient but faster than exp()
|
||||
*/
|
||||
double fast_exp2( const double val )
|
||||
{
|
||||
int e;
|
||||
double ret;
|
||||
|
||||
if (val >= 0) {
|
||||
e = int (val);
|
||||
ret = val - (e - 1);
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
((*((int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
|
||||
#else
|
||||
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
|
||||
#endif
|
||||
} else {
|
||||
e = int (val + 1023);
|
||||
ret = val - (e - 1024);
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
((*((int *) &ret)) &= ~(2047 << 20)) += e << 20;
|
||||
#else
|
||||
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
float _fast_log2(const float val)
|
||||
{
|
||||
float result, tmp;
|
||||
float mp = 0.346607f;
|
||||
|
||||
result = *(int*)&val;
|
||||
result *= 1.0/(1<<23);
|
||||
result = result - 127;
|
||||
|
||||
tmp = result - floor(result);
|
||||
tmp = (tmp - tmp*tmp) * mp;
|
||||
return tmp + result;
|
||||
}
|
||||
|
||||
float _fast_pow2(const float val)
|
||||
{
|
||||
float result;
|
||||
|
||||
float mp = 0.33971f;
|
||||
float tmp = val - floor(val);
|
||||
tmp = (tmp - tmp*tmp) * mp;
|
||||
|
||||
result = val + 127 - tmp;
|
||||
result *= (1<<23);
|
||||
*(int*)&result = (int)result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* While we're on the subject, someone might have use for these as well?
|
||||
* Float Shift Left and Float Shift Right. Do what you want with this.
|
||||
*/
|
||||
void fast_BSL(float &x, register unsigned long shiftAmount) {
|
||||
|
||||
*(unsigned long*)&x+=shiftAmount<<23;
|
||||
|
||||
}
|
||||
|
||||
void fast_BSR(float &x, register unsigned long shiftAmount) {
|
||||
|
||||
*(unsigned long*)&x-=shiftAmount<<23;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fastpow(f,n) gives a rather *rough* estimate of a float number f to the
|
||||
* power of an integer number n (y=f^n). It is fast but result can be quite a
|
||||
* bit off, since we directly mess with the floating point exponent.
|
||||
*
|
||||
* Use it only for getting rough estimates of the values and where precision
|
||||
* is not that important.
|
||||
*/
|
||||
float fast_pow(const float f, const int n)
|
||||
{
|
||||
long *lp,l;
|
||||
lp=(long*)(&f);
|
||||
l=*lp;l-=0x3F800000l;l<<=(n-1);l+=0x3F800000l;
|
||||
*lp=l;
|
||||
return f;
|
||||
}
|
||||
|
||||
float fast_root(const float f, const int n)
|
||||
{
|
||||
long *lp,l;
|
||||
lp=(long*)(&f);
|
||||
l=*lp;l-=0x3F800000l;l>>=(n-1);l+=0x3F800000l;
|
||||
*lp=l;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Code for approximation of cos, sin, tan and inv sin, etc.
|
||||
* Surprisingly accurate and very usable.
|
||||
*
|
||||
* Domain:
|
||||
* Sin/Cos [0, pi/2]
|
||||
* Tan [0,pi/4]
|
||||
* InvSin/Cos [0, 1]
|
||||
* InvTan [-1, 1]
|
||||
*/
|
||||
|
||||
float fast_sin(const float val)
|
||||
{
|
||||
float fASqr = val*val;
|
||||
float fResult = -2.39e-08f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.7526e-06f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 1.98409e-04f;
|
||||
fResult *= fASqr;
|
||||
fResult += 8.3333315e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 1.666666664e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.0f;
|
||||
fResult *= val;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_cos(const float val)
|
||||
{
|
||||
float fASqr = val*val;
|
||||
float fResult = -2.605e-07f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.47609e-05f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 1.3888397e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult += 4.16666418e-02f;
|
||||
fResult *= fASqr;
|
||||
fResult -= 4.999999963e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.0f;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_tan(const float val)
|
||||
{
|
||||
float fASqr = val*val;
|
||||
float fResult = 9.5168091e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.900525e-03f;
|
||||
fResult *= fASqr;
|
||||
fResult += 2.45650893e-02f;
|
||||
fResult *= fASqr;
|
||||
fResult += 5.33740603e-02f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.333923995e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 3.333314036e-01f;
|
||||
fResult *= fASqr;
|
||||
fResult += 1.0f;
|
||||
fResult *= val;
|
||||
|
||||
return fResult;
|
||||
|
||||
}
|
||||
|
||||
float fast_asin(float val)
|
||||
{
|
||||
float fRoot = sqrt(1.0f-val);
|
||||
float fResult = -0.0187293f;
|
||||
fResult *= val;
|
||||
fResult += 0.0742610f;
|
||||
fResult *= val;
|
||||
fResult -= 0.2121144f;
|
||||
fResult *= val;
|
||||
fResult += 1.5707288f;
|
||||
fResult = SGD_PI_2 - fRoot*fResult;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_acos(float val)
|
||||
{
|
||||
float fRoot = sqrt(1.0f-val);
|
||||
float fResult = -0.0187293f;
|
||||
fResult *= val;
|
||||
fResult += 0.0742610f;
|
||||
fResult *= val;
|
||||
fResult -= 0.2121144f;
|
||||
fResult *= val;
|
||||
fResult += 1.5707288f;
|
||||
fResult *= fRoot;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
float fast_atan(float val)
|
||||
{
|
||||
float fVSqr = val*val;
|
||||
float fResult = 0.0028662257f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.0161657367f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 0.0429096138f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.0752896400f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 0.1065626393f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.1420889944f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 0.1999355085f;
|
||||
fResult *= fVSqr;
|
||||
fResult -= 0.3333314528f;
|
||||
fResult *= fVSqr;
|
||||
fResult += 1.0f;
|
||||
fResult *= val;
|
||||
|
||||
return fResult;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* \file fastmath.hxx
|
||||
* fast mathematics routines.
|
||||
*
|
||||
* References:
|
||||
*
|
||||
* A Fast, Compact Approximation of the Exponential Function
|
||||
* Nicol N. Schraudolph
|
||||
* IDSIA, Lugano, Switzerland
|
||||
* http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
|
||||
*
|
||||
* Fast log() Function, by Laurent de Soras:
|
||||
* http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-Fastlogfunction&forum=totd&id=-1
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _SG_FMATH_HXX
|
||||
#define _SG_FMATH_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
double fast_exp(double val);
|
||||
double fast_exp2(const double val);
|
||||
|
||||
float fast_pow(const float val1, const float val2);
|
||||
float fast_log2(const float cal);
|
||||
float fast_root(const float f, const int n);
|
||||
|
||||
float _fast_pow2(const float cal);
|
||||
float _fast_log2(const float val);
|
||||
|
||||
float fast_sin(const float val);
|
||||
float fast_cos(const float val);
|
||||
float fast_tan(const float val);
|
||||
float fast_asin(const float val);
|
||||
float fast_acos(const float val);
|
||||
float fast_atan(const float val);
|
||||
|
||||
void fast_BSL(float &x, register unsigned long shiftAmount);
|
||||
void fast_BSR(float &x, register unsigned long shiftAmount);
|
||||
|
||||
|
||||
inline float fast_log2 (float val)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
int i;
|
||||
} v;
|
||||
v.f = val;
|
||||
const int log_2 = ((v.i >> 23) & 255) - 128;
|
||||
v.i &= ~(255 << 23);
|
||||
v.i += 127 << 23;
|
||||
|
||||
v.f = ((-1.0f/3) * v.f + 2) * v.f - 2.0f/3; // (1)
|
||||
|
||||
return (v.f + log_2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is about 3 times faster than the system log() function
|
||||
* and has an error of about 0.01%
|
||||
*/
|
||||
inline float fast_log (const float &val)
|
||||
{
|
||||
return (fast_log2 (val) * 0.69314718f);
|
||||
}
|
||||
|
||||
inline float fast_log10 (const float &val)
|
||||
{
|
||||
return (fast_log2(val) / 3.321928095f);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is about twice as fast as the system pow(x,y) function
|
||||
*/
|
||||
inline float fast_pow(const float val1, const float val2)
|
||||
{
|
||||
return _fast_pow2(val2 * _fast_log2(val1));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Haven't seen this elsewhere, probably because it is too obvious?
|
||||
* Anyway, these functions are intended for 32-bit floating point numbers
|
||||
* only and should work a bit faster than the regular ones.
|
||||
*/
|
||||
inline float fast_abs(float f)
|
||||
{
|
||||
int i=((*(int*)&f)&0x7fffffff);
|
||||
return (*(float*)&i);
|
||||
}
|
||||
|
||||
inline float fast_neg(float f)
|
||||
{
|
||||
int i=((*(int*)&f)^0x80000000);
|
||||
return (*(float*)&i);
|
||||
}
|
||||
|
||||
inline int fast_sgn(float f)
|
||||
{
|
||||
return 1+(((*(int*)&f)>>31)<<1);
|
||||
}
|
||||
|
||||
#endif // !_SG_FMATH_HXX
|
||||
|
||||
@@ -25,12 +25,11 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <stdlib.h> // for exit()
|
||||
|
||||
#include STL_STRING
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include "interpolater.hxx"
|
||||
|
||||
@@ -38,22 +37,29 @@ SG_USING_STD(string);
|
||||
|
||||
// Constructor -- starts with an empty table.
|
||||
SGInterpTable::SGInterpTable()
|
||||
: size(0)
|
||||
{
|
||||
}
|
||||
|
||||
SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
|
||||
{
|
||||
if (!interpolation)
|
||||
return;
|
||||
std::vector<SGPropertyNode_ptr> entries = interpolation->getChildren("entry");
|
||||
for (unsigned i = 0; i < entries.size(); ++i)
|
||||
addEntry(entries[i]->getDoubleValue("ind", 0.0),
|
||||
entries[i]->getDoubleValue("dep", 0.0));
|
||||
}
|
||||
|
||||
// Constructor -- loads the interpolation table from the specified
|
||||
// file
|
||||
SGInterpTable::SGInterpTable( const string& file )
|
||||
: size(0)
|
||||
{
|
||||
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
||||
|
||||
sg_gzifstream in( file );
|
||||
if ( !in.is_open() ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
||||
exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
in >> skipcomment;
|
||||
@@ -61,8 +67,7 @@ SGInterpTable::SGInterpTable( const string& file )
|
||||
double ind, dep;
|
||||
in >> ind >> dep;
|
||||
in >> skipws;
|
||||
table.push_back(Entry(ind, dep));
|
||||
size++;
|
||||
_table[ind] = dep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,51 +75,42 @@ SGInterpTable::SGInterpTable( const string& file )
|
||||
// Add an entry to the table.
|
||||
void SGInterpTable::addEntry (double ind, double dep)
|
||||
{
|
||||
table.push_back(Entry(ind,dep));
|
||||
size++;
|
||||
_table[ind] = dep;
|
||||
}
|
||||
|
||||
|
||||
// Given an x value, linearly interpolate the y value from the table
|
||||
double SGInterpTable::interpolate(double x) const
|
||||
{
|
||||
int i;
|
||||
double y;
|
||||
|
||||
if (size == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
while ( (i < size) && (x > table[i].ind) ) {
|
||||
// cout << " i = " << i << " table[i].ind = " << table[i].ind << endl;
|
||||
// cout << " size = " << size << endl;
|
||||
i++;
|
||||
}
|
||||
|
||||
// printf ("i = %d ", i);
|
||||
|
||||
if ( i <= 0 ) {
|
||||
SG_LOG( SG_MATH, SG_DEBUG,
|
||||
"interpolate(): lookup error, x to small = " << x );
|
||||
return table[0].dep;
|
||||
}
|
||||
|
||||
// cout << " table[size-1].ind = " << table[size-1].ind << endl;
|
||||
if ( i >= size ) {
|
||||
SG_LOG( SG_MATH, SG_DEBUG,
|
||||
"interpolate(): lookup error, x to big = " << x );
|
||||
return table[size-1].dep;
|
||||
}
|
||||
|
||||
// y = y1 + (y0 - y1)(x - x1) / (x0 - x1)
|
||||
y = table[i].dep +
|
||||
( (table[i-1].dep - table[i].dep) *
|
||||
(x - table[i].ind) ) /
|
||||
(table[i-1].ind - table[i].ind);
|
||||
|
||||
return(y);
|
||||
// Empty table??
|
||||
if (_table.empty())
|
||||
return 0;
|
||||
|
||||
// Find the table bounds for the requested input.
|
||||
Table::const_iterator upBoundIt = _table.upper_bound(x);
|
||||
// points to a value outside the map. That is we are out of range.
|
||||
// use the last entry
|
||||
if (upBoundIt == _table.end())
|
||||
return _table.rbegin()->second;
|
||||
|
||||
// points to the first key must be lower
|
||||
// use the first entry
|
||||
if (upBoundIt == _table.begin())
|
||||
return upBoundIt->second;
|
||||
|
||||
// we know that we do not stand at the beginning, so it is safe to do so
|
||||
Table::const_iterator loBoundIt = upBoundIt;
|
||||
--loBoundIt;
|
||||
|
||||
// Just do linear interpolation.
|
||||
double loBound = loBoundIt->first;
|
||||
double upBound = upBoundIt->first;
|
||||
double loVal = loBoundIt->second;
|
||||
double upVal = upBoundIt->second;
|
||||
|
||||
// division by zero should not happen since the std::map
|
||||
// has sorted out duplicate entries before. Also since we have a
|
||||
// map, we know that we get different first values for different iterators
|
||||
return loVal + (upVal - loVal)*(x - loBound)/(upBound - loBound);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,12 +35,14 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <vector>
|
||||
SG_USING_STD(vector);
|
||||
#include "simgear/structure/SGReferenced.hxx"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include STL_STRING
|
||||
SG_USING_STD(string);
|
||||
|
||||
class SGPropertyNode;
|
||||
|
||||
/**
|
||||
* A class that provids a simple linear 2d interpolation lookup table.
|
||||
@@ -48,21 +50,7 @@ SG_USING_STD(string);
|
||||
* independant variable must be strictly ascending. The dependent
|
||||
* variable can be anything.
|
||||
*/
|
||||
class SGInterpTable {
|
||||
|
||||
struct Entry
|
||||
{
|
||||
Entry ()
|
||||
: ind(0.0L), dep(0.0L) {}
|
||||
Entry (double independent, double dependent)
|
||||
: ind(independent), dep(dependent) {}
|
||||
double ind;
|
||||
double dep;
|
||||
};
|
||||
|
||||
int size;
|
||||
vector<Entry> table;
|
||||
|
||||
class SGInterpTable : public SGReferenced {
|
||||
public:
|
||||
|
||||
/**
|
||||
@@ -70,6 +58,13 @@ public:
|
||||
*/
|
||||
SGInterpTable();
|
||||
|
||||
/**
|
||||
* Constructor. Loads the interpolation table from an interpolation
|
||||
* property node.
|
||||
* @param interpolation property node having entry children
|
||||
*/
|
||||
SGInterpTable(const SGPropertyNode* interpolation);
|
||||
|
||||
/**
|
||||
* Constructor. Loads the interpolation table from the specified file.
|
||||
* @param file name of interpolation file
|
||||
@@ -95,6 +90,10 @@ public:
|
||||
|
||||
/** Destructor */
|
||||
~SGInterpTable();
|
||||
|
||||
private:
|
||||
typedef std::map<double, double> Table;
|
||||
Table _table;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
WARNING - Do not remove this header.
|
||||
|
||||
This code is a templated version of the 'magic-software' spherical
|
||||
interpolation code by Dave Eberly. The original (un-hacked) code can be
|
||||
obtained from here: http://www.magic-software.com/gr_appr.htm
|
||||
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
|
||||
|
||||
Dave Eberly says that the conditions for use are:
|
||||
|
||||
* You may distribute the original source code to others at no charge.
|
||||
|
||||
* You may modify the original source code and distribute it to others at
|
||||
no charge. The modified code must be documented to indicate that it is
|
||||
not part of the original package.
|
||||
|
||||
* You may use this code for non-commercial purposes. You may also
|
||||
incorporate this code into commercial packages. However, you may not
|
||||
sell any of your source code which contains my original and/or modified
|
||||
source code. In such a case, you need to factor out my code and freely
|
||||
distribute it.
|
||||
|
||||
* The original code comes with absolutely no warranty and no guarantee is
|
||||
made that the code is bug-free.
|
||||
|
||||
This does not seem incompatible with GPL - so this modified version
|
||||
is hereby placed under GPL along with the rest of FlightGear.
|
||||
|
||||
Christian Mayer
|
||||
*/
|
||||
|
||||
#ifndef LININTP2_H
|
||||
#define LININTP2_H
|
||||
|
||||
template<class T>
|
||||
class mgcLinInterp2D
|
||||
{
|
||||
public:
|
||||
mgcLinInterp2D (int _numPoints, double* x, double* y, T* _f);
|
||||
|
||||
~mgcLinInterp2D ();
|
||||
|
||||
double XMin () { return xmin; }
|
||||
double XMax () { return xmax; }
|
||||
double XRange () { return xmax-xmin; }
|
||||
double YMin () { return ymin; }
|
||||
double YMax () { return ymax; }
|
||||
double YRange () { return ymax-ymin; }
|
||||
|
||||
int PointCount () { return numPoints; }
|
||||
void GetPoint (int i, double& x, double& y);
|
||||
|
||||
int EdgeCount () { return numEdges; }
|
||||
void GetEdge (int i, double& x0, double& y0, double& x1, double& y1);
|
||||
|
||||
int TriangleCount () { return numTriangles; }
|
||||
void GetTriangle (int i, double& x0, double& y0, double& x1, double& y1,
|
||||
double& x2, double& y2);
|
||||
|
||||
int Evaluate (double x, double y, T& F);
|
||||
|
||||
private:
|
||||
typedef struct
|
||||
{
|
||||
double x, y;
|
||||
}
|
||||
Vertex;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int vertex[3]; // listed in counterclockwise order
|
||||
|
||||
int adj[3];
|
||||
// adj[0] points to triangle sharing edge (vertex[0],vertex[1])
|
||||
// adj[1] points to triangle sharing edge (vertex[1],vertex[2])
|
||||
// adj[2] points to triangle sharing edge (vertex[2],vertex[0])
|
||||
}
|
||||
Triangle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int vertex[2];
|
||||
int triangle[2];
|
||||
int index[2];
|
||||
}
|
||||
Edge;
|
||||
|
||||
int numPoints;
|
||||
double** point;
|
||||
double** tmppoint;
|
||||
T* f;
|
||||
|
||||
double xmin, xmax, ymin, ymax;
|
||||
|
||||
|
||||
int numEdges;
|
||||
Edge* edge;
|
||||
|
||||
int numTriangles;
|
||||
Triangle* triangle;
|
||||
|
||||
int Delaunay2D ();
|
||||
void ComputeBarycenter (Vertex& v0, Vertex& v1, Vertex& v2, Vertex& ver,
|
||||
double c[3]);
|
||||
int InTriangle (Vertex& v0, Vertex& v1, Vertex& v2, Vertex& test);
|
||||
};
|
||||
|
||||
#include "linintp2.inl"
|
||||
|
||||
#endif
|
||||
@@ -1,540 +0,0 @@
|
||||
/*
|
||||
WARNING - Do not remove this header.
|
||||
|
||||
This code is a templated version of the 'magic-software' spherical
|
||||
interpolation code by Dave Eberly. The original (un-hacked) code can be
|
||||
obtained from here: http://www.magic-software.com/gr_appr.htm
|
||||
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
|
||||
|
||||
Dave Eberly says that the conditions for use are:
|
||||
|
||||
* You may distribute the original source code to others at no charge.
|
||||
|
||||
* You may modify the original source code and distribute it to others at
|
||||
no charge. The modified code must be documented to indicate that it is
|
||||
not part of the original package.
|
||||
|
||||
* You may use this code for non-commercial purposes. You may also
|
||||
incorporate this code into commercial packages. However, you may not
|
||||
sell any of your source code which contains my original and/or modified
|
||||
source code. In such a case, you need to factor out my code and freely
|
||||
distribute it.
|
||||
|
||||
* The original code comes with absolutely no warranty and no guarantee is
|
||||
made that the code is bug-free.
|
||||
|
||||
This does not seem incompatible with GPL - so this modified version
|
||||
is hereby placed under GPL along with the rest of FlightGear.
|
||||
|
||||
Christian Mayer
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "linintp2.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
mgcLinInterp2D<T>::mgcLinInterp2D (int _numPoints, double* x, double* y,
|
||||
T* _f)
|
||||
{
|
||||
if ( (numPoints = _numPoints) < 3 )
|
||||
{
|
||||
point = 0;
|
||||
edge = 0;
|
||||
triangle = 0;
|
||||
numTriangles = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// cout << "[ 20%] allocating memory \r";
|
||||
|
||||
point = new double*[numPoints];
|
||||
tmppoint = new double*[numPoints+3];
|
||||
f = new T[numPoints];
|
||||
int i;
|
||||
for (i = 0; i < numPoints; i++)
|
||||
point[i] = new double[2];
|
||||
for (i = 0; i < numPoints+3; i++)
|
||||
tmppoint[i] = new double[2];
|
||||
for (i = 0; i < numPoints; i++)
|
||||
{
|
||||
point[i][0] = tmppoint[i][0] = x[i];
|
||||
point[i][1] = tmppoint[i][1] = y[i];
|
||||
|
||||
f[i] = _f[i];
|
||||
}
|
||||
|
||||
// cout << "[ 30%] creating delaunay diagram \r";
|
||||
|
||||
Delaunay2D();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
mgcLinInterp2D<T>::~mgcLinInterp2D ()
|
||||
{
|
||||
if ( numPoints < 3 )
|
||||
return;
|
||||
|
||||
int i;
|
||||
|
||||
if ( point )
|
||||
{
|
||||
for (i = 0; i < numPoints; i++)
|
||||
delete[] point[i];
|
||||
delete[] point;
|
||||
}
|
||||
if ( tmppoint )
|
||||
{
|
||||
for (i = 0; i < numPoints+3; i++)
|
||||
delete[] tmppoint[i];
|
||||
delete[] tmppoint;
|
||||
}
|
||||
|
||||
delete[] f;
|
||||
delete[] edge;
|
||||
delete[] triangle;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void mgcLinInterp2D<T>::ComputeBarycenter (Vertex& v0, Vertex& v1, Vertex& v2,
|
||||
Vertex& ver, double c[3])
|
||||
{
|
||||
double A0 = v0.x-v2.x, B0 = v0.y-v2.y;
|
||||
double A1 = v1.x-v2.x, B1 = v1.y-v2.y;
|
||||
double A2 = ver.x-v2.x, B2 = ver.y-v2.y;
|
||||
|
||||
double m00 = A0*A0+B0*B0, m01 = A0*A1+B0*B1, m11 = A1*A1+B1*B1;
|
||||
double r0 = A2*A0+B2*B0, r1 = A2*A1+B2*B1;
|
||||
double det = m00*m11-m01*m01;
|
||||
|
||||
c[0] = (m11*r0-m01*r1)/det;
|
||||
c[1] = (m00*r1-m01*r0)/det;
|
||||
c[2] = 1-c[0]-c[1];
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
int mgcLinInterp2D<T>::InTriangle (Vertex& v0, Vertex& v1, Vertex& v2,
|
||||
Vertex& test)
|
||||
{
|
||||
const double eps = 1e-08;
|
||||
double tx, ty, nx, ny;
|
||||
|
||||
// test against normal to first edge
|
||||
tx = test.x - v0.x;
|
||||
ty = test.y - v0.y;
|
||||
nx = v0.y - v1.y;
|
||||
ny = v1.x - v0.x;
|
||||
if ( tx*nx + ty*ny < -eps )
|
||||
return 0;
|
||||
|
||||
// test against normal to second edge
|
||||
tx = test.x - v1.x;
|
||||
ty = test.y - v1.y;
|
||||
nx = v1.y - v2.y;
|
||||
ny = v2.x - v1.x;
|
||||
if ( tx*nx + ty*ny < -eps )
|
||||
return 0;
|
||||
|
||||
// test against normal to third edge
|
||||
tx = test.x - v2.x;
|
||||
ty = test.y - v2.y;
|
||||
nx = v2.y - v0.y;
|
||||
ny = v0.x - v2.x;
|
||||
if ( tx*nx + ty*ny < -eps )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
int mgcLinInterp2D<T>::Evaluate (double x, double y, T& F)
|
||||
{
|
||||
Vertex ver = { x, y };
|
||||
// determine which triangle contains the target point
|
||||
|
||||
int i;
|
||||
Vertex v0, v1, v2;
|
||||
for (i = 0; i < numTriangles; i++)
|
||||
{
|
||||
Triangle& t = triangle[i];
|
||||
v0.x = point[t.vertex[0]][0];
|
||||
v0.y = point[t.vertex[0]][1];
|
||||
v1.x = point[t.vertex[1]][0];
|
||||
v1.y = point[t.vertex[1]][1];
|
||||
v2.x = point[t.vertex[2]][0];
|
||||
v2.y = point[t.vertex[2]][1];
|
||||
|
||||
if ( InTriangle(v0,v1,v2,ver) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( i == numTriangles ) // point is outside interpolation region
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Triangle& t = triangle[i]; // (x,y) is in this triangle
|
||||
|
||||
// compute barycentric coordinates with respect to subtriangle
|
||||
double bary[3];
|
||||
ComputeBarycenter(v0,v1,v2,ver,bary);
|
||||
|
||||
// compute barycentric combination of function values at vertices
|
||||
F = bary[0]*f[t.vertex[0]]+bary[1]*f[t.vertex[1]]+bary[2]*f[t.vertex[2]];
|
||||
|
||||
return 1;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
int mgcLinInterp2D<T>::Delaunay2D ()
|
||||
{
|
||||
int result;
|
||||
|
||||
const double EPSILON = 1e-12;
|
||||
const int TSIZE = 75;
|
||||
const double RANGE = 10.0;
|
||||
|
||||
xmin = tmppoint[0][0];
|
||||
xmax = xmin;
|
||||
ymin = tmppoint[0][1];
|
||||
ymax = ymin;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < numPoints; i++)
|
||||
{
|
||||
double value = tmppoint[i][0];
|
||||
if ( xmax < value )
|
||||
xmax = value;
|
||||
if ( xmin > value )
|
||||
xmin = value;
|
||||
|
||||
value = tmppoint[i][1];
|
||||
if ( ymax < value )
|
||||
ymax = value;
|
||||
if ( ymin > value )
|
||||
ymin = value;
|
||||
}
|
||||
|
||||
double xrange = xmax-xmin, yrange = ymax-ymin;
|
||||
double maxrange = xrange;
|
||||
if ( maxrange < yrange )
|
||||
maxrange = yrange;
|
||||
|
||||
// need to scale the data later to do a correct triangle count
|
||||
double maxrange2 = maxrange*maxrange;
|
||||
|
||||
// tweak the points by very small random numbers
|
||||
double bgs = EPSILON*maxrange;
|
||||
srand(367);
|
||||
for (i = 0; i < numPoints; i++)
|
||||
{
|
||||
tmppoint[i][0] += bgs*(0.5 - rand()/double(RAND_MAX));
|
||||
tmppoint[i][1] += bgs*(0.5 - rand()/double(RAND_MAX));
|
||||
}
|
||||
|
||||
double wrk[2][3] =
|
||||
{
|
||||
{ 5*RANGE, -RANGE, -RANGE },
|
||||
{ -RANGE, 5*RANGE, -RANGE }
|
||||
};
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
tmppoint[numPoints+i][0] = xmin+xrange*wrk[0][i];
|
||||
tmppoint[numPoints+i][1] = ymin+yrange*wrk[1][i];
|
||||
}
|
||||
|
||||
int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11;
|
||||
int nts, ii[3];
|
||||
double xx;
|
||||
|
||||
int tsz = 2*TSIZE;
|
||||
int** tmp = new int*[tsz+1];
|
||||
tmp[0] = new int[2*(tsz+1)];
|
||||
for (i0 = 1; i0 < tsz+1; i0++)
|
||||
tmp[i0] = tmp[0] + 2*i0;
|
||||
i1 = 2*(numPoints + 2);
|
||||
|
||||
int* id = new int[i1];
|
||||
for (i0 = 0; i0 < i1; i0++)
|
||||
id[i0] = i0;
|
||||
|
||||
int** a3s = new int*[i1];
|
||||
a3s[0] = new int[3*i1];
|
||||
for (i0 = 1; i0 < i1; i0++)
|
||||
a3s[i0] = a3s[0] + 3*i0;
|
||||
a3s[0][0] = numPoints;
|
||||
a3s[0][1] = numPoints+1;
|
||||
a3s[0][2] = numPoints+2;
|
||||
|
||||
double** ccr = new double*[i1]; // circumscribed centers and radii
|
||||
ccr[0] = new double[3*i1];
|
||||
for (i0 = 1; i0 < i1; i0++)
|
||||
ccr[i0] = ccr[0] + 3*i0;
|
||||
ccr[0][0] = 0.0;
|
||||
ccr[0][1] = 0.0;
|
||||
ccr[0][2] = FLT_MAX;
|
||||
|
||||
nts = 1; // number of triangles
|
||||
i4 = 1;
|
||||
|
||||
// cout << "[ 40%] create triangulation \r";
|
||||
|
||||
// compute triangulation
|
||||
for (i0 = 0; i0 < numPoints; i0++)
|
||||
{
|
||||
i1 = i7 = -1;
|
||||
i9 = 0;
|
||||
for (i11 = 0; i11 < nts; i11++)
|
||||
{
|
||||
i1++;
|
||||
while ( a3s[i1][0] < 0 )
|
||||
i1++;
|
||||
xx = ccr[i1][2];
|
||||
for (i2 = 0; i2 < 2; i2++)
|
||||
{
|
||||
double z = tmppoint[i0][i2]-ccr[i1][i2];
|
||||
xx -= z*z;
|
||||
if ( xx < 0 )
|
||||
goto Corner3;
|
||||
}
|
||||
i9--;
|
||||
i4--;
|
||||
id[i4] = i1;
|
||||
for (i2 = 0; i2 < 3; i2++)
|
||||
{
|
||||
ii[0] = 0;
|
||||
if (ii[0] == i2)
|
||||
ii[0]++;
|
||||
for (i3 = 1; i3 < 2; i3++)
|
||||
{
|
||||
ii[i3] = ii[i3-1] + 1;
|
||||
if (ii[i3] == i2)
|
||||
ii[i3]++;
|
||||
}
|
||||
if ( i7 > 1 )
|
||||
{
|
||||
i8 = i7;
|
||||
for (i3 = 0; i3 <= i8; i3++)
|
||||
{
|
||||
for (i5 = 0; i5 < 2; i5++)
|
||||
if ( a3s[i1][ii[i5]] != tmp[i3][i5] )
|
||||
goto Corner1;
|
||||
for (i6 = 0; i6 < 2; i6++)
|
||||
tmp[i3][i6] = tmp[i8][i6];
|
||||
i7--;
|
||||
goto Corner2;
|
||||
Corner1:;
|
||||
}
|
||||
}
|
||||
if ( ++i7 > tsz )
|
||||
{
|
||||
// temporary storage exceeded, increase TSIZE
|
||||
result = 0;
|
||||
goto ExitDelaunay;
|
||||
}
|
||||
for (i3 = 0; i3 < 2; i3++)
|
||||
tmp[i7][i3] = a3s[i1][ii[i3]];
|
||||
Corner2:;
|
||||
}
|
||||
a3s[i1][0] = -1;
|
||||
Corner3:;
|
||||
}
|
||||
|
||||
for (i1 = 0; i1 <= i7; i1++)
|
||||
{
|
||||
for (i2 = 0; i2 < 2; i2++)
|
||||
for (wrk[i2][2] = 0, i3 = 0; i3 < 2; i3++)
|
||||
{
|
||||
wrk[i2][i3] = tmppoint[tmp[i1][i2]][i3]-tmppoint[i0][i3];
|
||||
wrk[i2][2] +=
|
||||
0.5*wrk[i2][i3]*(tmppoint[tmp[i1][i2]][i3]+
|
||||
tmppoint[i0][i3]);
|
||||
}
|
||||
|
||||
xx = wrk[0][0]*wrk[1][1]-wrk[1][0]*wrk[0][1];
|
||||
ccr[id[i4]][0] = (wrk[0][2]*wrk[1][1]-wrk[1][2]*wrk[0][1])/xx;
|
||||
ccr[id[i4]][1] = (wrk[0][0]*wrk[1][2]-wrk[1][0]*wrk[0][2])/xx;
|
||||
|
||||
for (ccr[id[i4]][2] = 0, i2 = 0; i2 < 2; i2++)
|
||||
{
|
||||
double z = tmppoint[i0][i2]-ccr[id[i4]][i2];
|
||||
ccr[id[i4]][2] += z*z;
|
||||
a3s[id[i4]][i2] = tmp[i1][i2];
|
||||
}
|
||||
|
||||
a3s[id[i4]][2] = i0;
|
||||
i4++;
|
||||
i9++;
|
||||
}
|
||||
nts += i9;
|
||||
}
|
||||
|
||||
// count the number of triangles
|
||||
// cout << "[ 50%] count the number of triangles \r";
|
||||
|
||||
numTriangles = 0;
|
||||
i0 = -1;
|
||||
for (i11 = 0; i11 < nts; i11++)
|
||||
{
|
||||
i0++;
|
||||
while ( a3s[i0][0] < 0 )
|
||||
i0++;
|
||||
if ( a3s[i0][0] < numPoints )
|
||||
{
|
||||
for (i1 = 0; i1 < 2; i1++)
|
||||
for (i2 = 0; i2 < 2; i2++)
|
||||
wrk[i1][i2] =
|
||||
tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
|
||||
|
||||
if ( fabs(wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0]) > EPSILON*maxrange2 )
|
||||
numTriangles++;
|
||||
}
|
||||
}
|
||||
|
||||
// create the triangles
|
||||
// cout << "[ 60%] create the triangles \r";
|
||||
|
||||
triangle = new Triangle[numTriangles];
|
||||
|
||||
numTriangles = 0;
|
||||
i0 = -1;
|
||||
for (i11 = 0; i11 < nts; i11++)
|
||||
{
|
||||
i0++;
|
||||
while ( a3s[i0][0] < 0 )
|
||||
i0++;
|
||||
if ( a3s[i0][0] < numPoints )
|
||||
{
|
||||
for (i1 = 0; i1 < 2; i1++)
|
||||
for (i2 = 0; i2 < 2; i2++)
|
||||
wrk[i1][i2] =
|
||||
tmppoint[a3s[i0][i1]][i2]-tmppoint[a3s[i0][2]][i2];
|
||||
xx = wrk[0][0]*wrk[1][1]-wrk[0][1]*wrk[1][0];
|
||||
if ( fabs(xx) > EPSILON*maxrange2 )
|
||||
{
|
||||
int delta = xx < 0 ? 1 : 0;
|
||||
Triangle& tri = triangle[numTriangles];
|
||||
tri.vertex[0] = a3s[i0][0];
|
||||
tri.vertex[1] = a3s[i0][1+delta];
|
||||
tri.vertex[2] = a3s[i0][2-delta];
|
||||
tri.adj[0] = -1;
|
||||
tri.adj[1] = -1;
|
||||
tri.adj[2] = -1;
|
||||
numTriangles++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build edge table
|
||||
// cout << "[ 70%] build the edge table \r";
|
||||
|
||||
numEdges = 0;
|
||||
edge = new Edge[3*numTriangles];
|
||||
|
||||
int j, j0, j1;
|
||||
for (i = 0; i < numTriangles; i++)
|
||||
{
|
||||
// if ( (i%500) == 0)
|
||||
// cout << "[ 7" << 10*i/numTriangles << "%] build the edge table \r";
|
||||
|
||||
Triangle& t = triangle[i];
|
||||
|
||||
for (j0 = 0, j1 = 1; j0 < 3; j0++, j1 = (j1+1)%3)
|
||||
{
|
||||
for (j = 0; j < numEdges; j++)
|
||||
{
|
||||
Edge& e = edge[j];
|
||||
if ( (t.vertex[j0] == e.vertex[0]
|
||||
&& t.vertex[j1] == e.vertex[1])
|
||||
|| (t.vertex[j0] == e.vertex[1]
|
||||
&& t.vertex[j1] == e.vertex[0]) )
|
||||
break;
|
||||
}
|
||||
if ( j == numEdges ) // add edge to table
|
||||
{
|
||||
edge[j].vertex[0] = t.vertex[j0];
|
||||
edge[j].vertex[1] = t.vertex[j1];
|
||||
edge[j].triangle[0] = i;
|
||||
edge[j].index[0] = j0;
|
||||
edge[j].triangle[1] = -1;
|
||||
numEdges++;
|
||||
}
|
||||
else // edge already exists, add triangle to table
|
||||
{
|
||||
edge[j].triangle[1] = i;
|
||||
edge[j].index[1] = j0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// establish links between adjacent triangles
|
||||
// cout << "[ 80%] establishing links between adjacent triangles \r";
|
||||
|
||||
for (i = 0; i < numEdges; i++)
|
||||
{
|
||||
if ( edge[i].triangle[1] != -1 )
|
||||
{
|
||||
j0 = edge[i].triangle[0];
|
||||
j1 = edge[i].triangle[1];
|
||||
triangle[j0].adj[edge[i].index[0]] = j1;
|
||||
triangle[j1].adj[edge[i].index[1]] = j0;
|
||||
}
|
||||
}
|
||||
|
||||
result = 1;
|
||||
|
||||
ExitDelaunay:;
|
||||
delete[] tmp[0];
|
||||
delete[] tmp;
|
||||
delete[] id;
|
||||
delete[] a3s[0];
|
||||
delete[] a3s;
|
||||
delete[] ccr[0];
|
||||
delete[] ccr;
|
||||
|
||||
// cout << "[ 90%] finsishes delauney triangulation \r";
|
||||
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void mgcLinInterp2D<T>::GetPoint (int i, double& x, double& y)
|
||||
{
|
||||
// assumes i is valid [can use PointCount() before passing i]
|
||||
x = point[i][0];
|
||||
y = point[i][1];
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void mgcLinInterp2D<T>::GetEdge (int i, double& x0, double& y0, double& x1,
|
||||
double& y1)
|
||||
{
|
||||
// assumes i is valid [can use EdgeCount() before passing i]
|
||||
int v0 = edge[i].vertex[0], v1 = edge[i].vertex[1];
|
||||
|
||||
x0 = point[v0][0];
|
||||
y0 = point[v0][1];
|
||||
x1 = point[v1][0];
|
||||
y1 = point[v1][1];
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void mgcLinInterp2D<T>::GetTriangle (int i, double& x0, double& y0, double& x1,
|
||||
double& y1, double& x2, double& y2)
|
||||
{
|
||||
// assumes i is valid [can use TriangleCount() before passing i]
|
||||
int v0 = triangle[i].vertex[0];
|
||||
int v1 = triangle[i].vertex[1];
|
||||
int v2 = triangle[i].vertex[2];
|
||||
|
||||
x0 = point[v0][0];
|
||||
y0 = point[v0][1];
|
||||
x1 = point[v1][0];
|
||||
y1 = point[v1][1];
|
||||
x2 = point[v2][0];
|
||||
y2 = point[v2][1];
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
static Point3D fromSGGeod(const SGGeod& geod);
|
||||
static Point3D fromSGGeoc(const SGGeoc& geoc);
|
||||
static Point3D fromSGVec3(const SGVec3<double>& cart);
|
||||
static Point3D fromSGVec3(const SGVec3<float>& cart);
|
||||
static Point3D fromSGVec2(const SGVec2<double>& cart);
|
||||
|
||||
// Assignment operators
|
||||
|
||||
@@ -132,6 +134,10 @@ public:
|
||||
SGGeod toSGGeod(void) const;
|
||||
SGGeoc toSGGeoc(void) const;
|
||||
|
||||
SGVec3d toSGVec3d(void) const;
|
||||
SGVec3f toSGVec3f(void) const;
|
||||
SGVec2f toSGVec2f(void) const;
|
||||
|
||||
// friends
|
||||
friend Point3D operator - (const Point3D& p); // -p1
|
||||
friend bool operator == (const Point3D& a, const Point3D& b); // p1 == p2?
|
||||
@@ -239,6 +245,24 @@ inline Point3D Point3D::fromSGVec3(const SGVec3<double>& cart)
|
||||
return pt;
|
||||
}
|
||||
|
||||
inline Point3D Point3D::fromSGVec3(const SGVec3<float>& cart)
|
||||
{
|
||||
Point3D pt;
|
||||
pt.setx(cart.x());
|
||||
pt.sety(cart.y());
|
||||
pt.setz(cart.z());
|
||||
return pt;
|
||||
}
|
||||
|
||||
inline Point3D Point3D::fromSGVec2(const SGVec2<double>& cart)
|
||||
{
|
||||
Point3D pt;
|
||||
pt.setx(cart.x());
|
||||
pt.sety(cart.y());
|
||||
pt.setz(0);
|
||||
return pt;
|
||||
}
|
||||
|
||||
// ASSIGNMENT OPERATORS
|
||||
|
||||
inline Point3D& Point3D::operator = (const Point3D& p)
|
||||
@@ -341,6 +365,21 @@ inline SGGeoc Point3D::toSGGeoc(void) const
|
||||
return geoc;
|
||||
}
|
||||
|
||||
inline SGVec3d Point3D::toSGVec3d(void) const
|
||||
{
|
||||
return SGVec3d(x(), y(), z());
|
||||
}
|
||||
|
||||
inline SGVec3f Point3D::toSGVec3f(void) const
|
||||
{
|
||||
return SGVec3f(x(), y(), z());
|
||||
}
|
||||
|
||||
inline SGVec2f Point3D::toSGVec2f(void) const
|
||||
{
|
||||
return SGVec2f(x(), y());
|
||||
}
|
||||
|
||||
// FRIENDS
|
||||
|
||||
inline Point3D operator - (const Point3D& a)
|
||||
|
||||
@@ -73,10 +73,9 @@ static inline double M0( double e2 ) {
|
||||
}
|
||||
|
||||
|
||||
// given, alt, lat1, lon1, az1 and distance (s), calculate lat2, lon2
|
||||
// given, lat1, lon1, az1 and distance (s), calculate lat2, lon2
|
||||
// and az2. Lat, lon, and azimuth are in degrees. distance in meters
|
||||
int geo_direct_wgs_84 ( double alt, double lat1,
|
||||
double lon1, double az1,
|
||||
int geo_direct_wgs_84 ( double lat1, double lon1, double az1,
|
||||
double s, double *lat2, double *lon2,
|
||||
double *az2 )
|
||||
{
|
||||
@@ -160,16 +159,15 @@ int geo_direct_wgs_84 ( double alt, double lat1,
|
||||
double dM = a*M0(e2) - s;
|
||||
double paz = ( phi1 < 0.0 ? 180.0 : 0.0 );
|
||||
double zero = 0.0f;
|
||||
return geo_direct_wgs_84( alt, zero, lon1, paz, dM, lat2, lon2, az2 );
|
||||
return geo_direct_wgs_84( zero, lon1, paz, dM, lat2, lon2, az2 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// given alt, lat1, lon1, lat2, lon2, calculate starting and ending
|
||||
// given lat1, lon1, lat2, lon2, calculate starting and ending
|
||||
// az1, az2 and distance (s). Lat, lon, and azimuth are in degrees.
|
||||
// distance in meters
|
||||
int geo_inverse_wgs_84( double alt, double lat1,
|
||||
double lon1, double lat2,
|
||||
int geo_inverse_wgs_84( double lat1, double lon1, double lat2,
|
||||
double lon2, double *az1, double *az2,
|
||||
double *s )
|
||||
{
|
||||
@@ -192,14 +190,14 @@ int geo_inverse_wgs_84( double alt, double lat1,
|
||||
return 0;
|
||||
} else if( fabs(cosphi1) < testv ) {
|
||||
// initial point is polar
|
||||
int k = geo_inverse_wgs_84( alt, lat2,lon2,lat1,lon1, az1,az2,s );
|
||||
int k = geo_inverse_wgs_84( lat2,lon2,lat1,lon1, az1,az2,s );
|
||||
k = k; // avoid compiler error since return result is unused
|
||||
b = *az1; *az1 = *az2; *az2 = b;
|
||||
return 0;
|
||||
} else if( fabs(cosphi2) < testv ) {
|
||||
// terminal point is polar
|
||||
double _lon1 = lon1 + 180.0f;
|
||||
int k = geo_inverse_wgs_84( alt, lat1, lon1, lat1, _lon1,
|
||||
int k = geo_inverse_wgs_84( lat1, lon1, lat1, _lon1,
|
||||
az1, az2, s );
|
||||
k = k; // avoid compiler error since return result is unused
|
||||
*s /= 2.0;
|
||||
@@ -211,8 +209,8 @@ int geo_inverse_wgs_84( double alt, double lat1,
|
||||
{
|
||||
// Geodesic passes through the pole (antipodal)
|
||||
double s1,s2;
|
||||
geo_inverse_wgs_84( alt, lat1,lon1, lat1,lon2, az1,az2, &s1 );
|
||||
geo_inverse_wgs_84( alt, lat2,lon2, lat1,lon2, az1,az2, &s2 );
|
||||
geo_inverse_wgs_84( lat1,lon1, lat1,lon2, az1,az2, &s1 );
|
||||
geo_inverse_wgs_84( lat2,lon2, lat1,lon2, az1,az2, &s2 );
|
||||
*az2 = *az1;
|
||||
*s = s1 + s2;
|
||||
return 0;
|
||||
|
||||
+54
-20
@@ -4,18 +4,6 @@
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include "SGMath.hxx"
|
||||
|
||||
// Returns the insersection of the line joining the center of the
|
||||
// earth and the specified cylindrical point with the surface of the
|
||||
// WGS84 ellipsoid. Works by finding a normalization constant (in
|
||||
// squashed space) that places the squashed point on the surface of
|
||||
// the sphere.
|
||||
inline double seaLevelRadius(double r, double z)
|
||||
{
|
||||
double sr = r * SGGeodesy::SQUASH;
|
||||
double zz = z*z;
|
||||
return SGGeodesy::POLRAD*sqrt((r*r + zz)/(sr*sr + zz));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from geocentric coordinates to geodetic coordinates
|
||||
* @param lat_geoc (in) Geocentric latitude, radians, + = North
|
||||
@@ -56,11 +44,12 @@ inline void sgGeodToGeoc(double lat_geod, double alt,
|
||||
double *sl_radius, double *lat_geoc)
|
||||
{
|
||||
SGVec3<double> cart;
|
||||
SGGeodesy::SGGeodToCart(SGGeod::fromRadM(0, lat_geod, alt), cart);
|
||||
SGGeod geod = SGGeod::fromRadM(0, lat_geod, alt);
|
||||
SGGeodesy::SGGeodToCart(geod, cart);
|
||||
SGGeoc geoc;
|
||||
SGGeodesy::SGCartToGeoc(cart, geoc);
|
||||
*lat_geoc = geoc.getLatitudeRad();
|
||||
*sl_radius = seaLevelRadius(cart(0), cart(2));
|
||||
*sl_radius = SGGeodesy::SGGeodToSeaLevelRadius(geod);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +119,7 @@ inline Point3D sgGeodToCart(const Point3D& geod)
|
||||
/**
|
||||
* Given a starting position and an offset radial and distance,
|
||||
* calculate an ending positon on a wgs84 ellipsoid.
|
||||
* @param alt (in) meters
|
||||
* @param alt (in) meters (unused)
|
||||
* @param lat1 (in) degrees
|
||||
* @param lon1 (in) degrees
|
||||
* @param az1 (in) degrees
|
||||
@@ -139,16 +128,39 @@ inline Point3D sgGeodToCart(const Point3D& geod)
|
||||
* @param lon2 (out) degrees
|
||||
* @param az2 (out) return course in degrees
|
||||
*/
|
||||
int geo_direct_wgs_84 ( double alt, double lat1,
|
||||
double lon1, double az1,
|
||||
int geo_direct_wgs_84 ( double lat1, double lon1, double az1,
|
||||
double s, double *lat2, double *lon2,
|
||||
double *az2 );
|
||||
inline int geo_direct_wgs_84 ( double alt, double lat1,
|
||||
double lon1, double az1,
|
||||
double s, double *lat2, double *lon2,
|
||||
double *az2 )
|
||||
{ return geo_direct_wgs_84(lat1, lon1, az1, s, lat2, lon2, az2); }
|
||||
|
||||
/**
|
||||
* Given a starting position and an offset radial and distance,
|
||||
* calculate an ending positon on a wgs84 ellipsoid.
|
||||
* @param p1 (in) geodetic position
|
||||
* @param az1 (in) degrees
|
||||
* @param s (in) distance in meters
|
||||
* @param p2 (out) geodetic position
|
||||
* @param az2 (out) return course in degrees
|
||||
*/
|
||||
inline int geo_direct_wgs_84(const SGGeod& p1, double az1,
|
||||
double s, SGGeod& p2, double *az2 )
|
||||
{
|
||||
double lat2, lon2;
|
||||
int ret = geo_direct_wgs_84(p1.getLatitudeDeg(), p1.getLongitudeDeg(),
|
||||
az1, s, &lat2, &lon2, az2);
|
||||
p2.setLatitudeDeg(lat2);
|
||||
p2.setLongitudeDeg(lon2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an altitude and two sets of (lat, lon) calculate great circle
|
||||
* distance between them as well as the starting and ending azimuths.
|
||||
* @param alt (in) meters
|
||||
* @param alt (in) meters (unused)
|
||||
* @param lat1 (in) degrees
|
||||
* @param lon1 (in) degrees
|
||||
* @param lat2 (in) degrees
|
||||
@@ -157,9 +169,31 @@ int geo_direct_wgs_84 ( double alt, double lat1,
|
||||
* @param az2 (out) end heading degrees
|
||||
* @param s (out) distance meters
|
||||
*/
|
||||
int geo_inverse_wgs_84( double alt, double lat1,
|
||||
double lon1, double lat2,
|
||||
int geo_inverse_wgs_84( double lat1, double lon1, double lat2,
|
||||
double lon2, double *az1, double *az2,
|
||||
double *s );
|
||||
inline int geo_inverse_wgs_84( double alt, double lat1,
|
||||
double lon1, double lat2,
|
||||
double lon2, double *az1, double *az2,
|
||||
double *s )
|
||||
{ return geo_inverse_wgs_84(lat1, lon1, lat2, lon2, az1, az2, s); }
|
||||
|
||||
|
||||
/**
|
||||
* Given an altitude and two sets of (lat, lon) calculate great circle
|
||||
* distance between them as well as the starting and ending azimuths.
|
||||
* @param p1 (in) first position
|
||||
* @param p2 (in) fsecond position
|
||||
* @param az1 (out) start heading degrees
|
||||
* @param az2 (out) end heading degrees
|
||||
* @param s (out) distance meters
|
||||
*/
|
||||
inline int geo_inverse_wgs_84(const SGGeod& p1, const SGGeod& p2,
|
||||
double *az1, double *az2, double *s )
|
||||
{
|
||||
return geo_inverse_wgs_84(p1.getLatitudeDeg(), p1.getLongitudeDeg(),
|
||||
p2.getLatitudeDeg(), p2.getLongitudeDeg(),
|
||||
az1, az2, s);
|
||||
}
|
||||
|
||||
#endif // _SG_GEODESY_HXX
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
WARNING - Do not remove this header.
|
||||
|
||||
This code is a templated version of the 'magic-software' spherical
|
||||
interpolation code by Dave Eberly. The original (un-hacked) code can be
|
||||
obtained from here: http://www.magic-software.com/gr_appr.htm
|
||||
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
|
||||
|
||||
Dave Eberly says that the conditions for use are:
|
||||
|
||||
* You may distribute the original source code to others at no charge.
|
||||
|
||||
* You may modify the original source code and distribute it to others at
|
||||
no charge. The modified code must be documented to indicate that it is
|
||||
not part of the original package.
|
||||
|
||||
* You may use this code for non-commercial purposes. You may also
|
||||
incorporate this code into commercial packages. However, you may not
|
||||
sell any of your source code which contains my original and/or modified
|
||||
source code. In such a case, you need to factor out my code and freely
|
||||
distribute it.
|
||||
|
||||
* The original code comes with absolutely no warranty and no guarantee is
|
||||
made that the code is bug-free.
|
||||
|
||||
This does not seem incompatible with GPL - so this modified version
|
||||
is hereby placed under GPL along with the rest of FlightGear.
|
||||
|
||||
Christian Mayer
|
||||
*/
|
||||
|
||||
#ifndef SPHRINTP_H
|
||||
#define SPHRINTP_H
|
||||
|
||||
#include "linintp2.h"
|
||||
#include <plib/sg.h>
|
||||
|
||||
template<class T>
|
||||
class SphereInterpolate
|
||||
{
|
||||
public:
|
||||
SphereInterpolate (int n, const double* x, const double* y,
|
||||
const double* z, const T* f);
|
||||
SphereInterpolate (int n, const sgVec2* p, const T* f);
|
||||
|
||||
~SphereInterpolate ();
|
||||
|
||||
void GetSphericalCoords (const double x, const double y, const double z,
|
||||
double& thetaAngle, double& phiAngle) const;
|
||||
|
||||
int Evaluate (const double x, const double y, const double z, T& f) const;
|
||||
int Evaluate (const double thetaAngle, const double phiAngle, T& f) const;
|
||||
|
||||
T Evaluate(const sgVec2& p) const
|
||||
{
|
||||
T retval;
|
||||
Evaluate(p[1], p[0], retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
T Evaluate(const sgVec3& p) const
|
||||
{
|
||||
T retval;
|
||||
Evaluate(p[1], p[0], retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
protected:
|
||||
int numPoints;
|
||||
double* theta;
|
||||
double* phi;
|
||||
T* func;
|
||||
mgcLinInterp2D<T>* pInterp;
|
||||
};
|
||||
|
||||
#include "sphrintp.inl"
|
||||
|
||||
#endif
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
WARNING - Do not remove this header.
|
||||
|
||||
This code is a templated version of the 'magic-software' spherical
|
||||
interpolation code by Dave Eberly. The original (un-hacked) code can be
|
||||
obtained from here: http://www.magic-software.com/gr_appr.htm
|
||||
This code is derived from linintp2.h/cpp and sphrintp.h/cpp.
|
||||
|
||||
Dave Eberly says that the conditions for use are:
|
||||
|
||||
* You may distribute the original source code to others at no charge.
|
||||
|
||||
* You may modify the original source code and distribute it to others at
|
||||
no charge. The modified code must be documented to indicate that it is
|
||||
not part of the original package.
|
||||
|
||||
* You may use this code for non-commercial purposes. You may also
|
||||
incorporate this code into commercial packages. However, you may not
|
||||
sell any of your source code which contains my original and/or modified
|
||||
source code. In such a case, you need to factor out my code and freely
|
||||
distribute it.
|
||||
|
||||
* The original code comes with absolutely no warranty and no guarantee is
|
||||
made that the code is bug-free.
|
||||
|
||||
This does not seem incompatible with GPL - so this modified version
|
||||
is hereby placed under GPL along with the rest of FlightGear.
|
||||
|
||||
Christian Mayer
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "sphrintp.h"
|
||||
|
||||
static const double PI = 4.0*atan(1.0);
|
||||
static const double TWOPI = 2.0*PI;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
SphereInterpolate<T>::SphereInterpolate (int n, const double* x,
|
||||
const double* y, const double* z,
|
||||
const T* f)
|
||||
{
|
||||
// Assumes (x[i],y[i],z[i]) is unit length for all 0 <= i < n.
|
||||
// For complete spherical coverage, include the two antipodal points
|
||||
// (0,0,1,f(0,0,1)) and (0,0,-1,f(0,0,-1)) in the data set.
|
||||
|
||||
// cout << "Initialising spherical interpolator.\n";
|
||||
// cout << "[ 0%] Allocating memory \r";
|
||||
|
||||
theta = new double[3*n];
|
||||
phi = new double[3*n];
|
||||
func = new T[3*n];
|
||||
|
||||
// convert data to spherical coordinates
|
||||
int i;
|
||||
T empty;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GetSphericalCoords(x[i],y[i],z[i],theta[i],phi[i]);
|
||||
func[i] = f[i];
|
||||
}
|
||||
|
||||
// use periodicity to get wrap-around in the Delaunay triangulation
|
||||
// cout << "[ 10%] copying vertices for wrap-around\r";
|
||||
int j, k;
|
||||
for (i = 0, j = n, k = 2*n; i < n; i++, j++, k++)
|
||||
{
|
||||
theta[j] = theta[i]+TWOPI;
|
||||
theta[k] = theta[i]-TWOPI;
|
||||
phi[j] = phi[i];
|
||||
phi[k] = phi[i];
|
||||
func[j] = func[i];
|
||||
func[k] = func[i];
|
||||
}
|
||||
|
||||
pInterp = new mgcLinInterp2D<T>(3*n,theta,phi,func);
|
||||
|
||||
// cout << "[100%] Finished initialising spherical interpolator. \n";
|
||||
}
|
||||
|
||||
template<class T>
|
||||
SphereInterpolate<T>::SphereInterpolate (int n, const sgVec2* p, const T* f)
|
||||
{
|
||||
// Assumes (x[i],y[i],z[i]) is unit length for all 0 <= i < n.
|
||||
// For complete spherical coverage, include the two antipodal points
|
||||
// (0,0,1,f(0,0,1)) and (0,0,-1,f(0,0,-1)) in the data set.
|
||||
// cout << "Initialising spherical interpolator.\n";
|
||||
// cout << "[ 0%] Allocating memory \r";
|
||||
|
||||
theta = new double[3*n];
|
||||
phi = new double[3*n];
|
||||
func = new T[3*n];
|
||||
|
||||
// convert data to spherical coordinates
|
||||
// cout << "[ 10%] copying vertices for wrap-around \r";
|
||||
|
||||
int i, j, k;
|
||||
for (i = 0, j = n, k = 2*n; i < n; i++, j++, k++)
|
||||
{
|
||||
phi[i] = p[i][0];
|
||||
theta[i] = p[i][1];
|
||||
func[i] = f[i];
|
||||
|
||||
// use periodicity to get wrap-around in the Delaunay triangulation
|
||||
phi[j] = phi[i];
|
||||
phi[k] = phi[i];
|
||||
theta[j] = theta[i]+TWOPI;
|
||||
theta[k] = theta[i]-TWOPI;
|
||||
func[j] = func[i];
|
||||
func[k] = func[i];
|
||||
}
|
||||
|
||||
pInterp = new mgcLinInterp2D<T>(3*n,theta,phi,func);
|
||||
|
||||
// cout << "[100%] Finished initialising spherical interpolator. \n";
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
SphereInterpolate<T>::~SphereInterpolate ()
|
||||
{
|
||||
delete pInterp;
|
||||
delete[] theta;
|
||||
delete[] phi;
|
||||
delete[] func;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void SphereInterpolate<T>::GetSphericalCoords (const double x, const double y, const double z,
|
||||
double& thetaAngle,
|
||||
double& phiAngle) const
|
||||
{
|
||||
// Assumes (x,y,z) is unit length. Returns -PI <= thetaAngle <= PI
|
||||
// and 0 <= phiAngle <= PI.
|
||||
|
||||
if ( z < 1.0f )
|
||||
{
|
||||
if ( z > -1.0f )
|
||||
{
|
||||
thetaAngle = atan2(y,x);
|
||||
phiAngle = acos(z);
|
||||
}
|
||||
else
|
||||
{
|
||||
thetaAngle = -PI;
|
||||
phiAngle = PI;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thetaAngle = -PI;
|
||||
phiAngle = 0.0f;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
int SphereInterpolate<T>::Evaluate (const double x, const double y, const double z, T& f) const
|
||||
{
|
||||
// assumes (x,y,z) is unit length
|
||||
|
||||
double thetaAngle, phiAngle;
|
||||
GetSphericalCoords(x,y,z,thetaAngle,phiAngle);
|
||||
return pInterp->Evaluate(thetaAngle,phiAngle,f);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
template<class T>
|
||||
int SphereInterpolate<T>::Evaluate (const double thetaAngle, const double phiAngle, T& f) const
|
||||
{
|
||||
return pInterp->Evaluate(thetaAngle,phiAngle,f);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -195,6 +195,8 @@ bool SGPath::exists() const {
|
||||
|
||||
void SGPath::create_dir( mode_t mode ) {
|
||||
string_list dirlist = sgPathSplit(dir());
|
||||
if ( dirlist.empty() )
|
||||
return;
|
||||
string path = dirlist[0];
|
||||
string_list path_elements = sgPathBranchSplit(path);
|
||||
bool absolute = !path.empty() && path[0] == sgDirPathSep;
|
||||
|
||||
@@ -2,26 +2,12 @@ includedir = @includedir@/nasal
|
||||
|
||||
lib_LIBRARIES = libsgnasal.a
|
||||
|
||||
include_HEADERS = nasal.h
|
||||
include_HEADERS = nasal.h naref.h
|
||||
|
||||
libsgnasal_a_SOURCES = \
|
||||
code.c code.h \
|
||||
codegen.c \
|
||||
data.h \
|
||||
gc.c \
|
||||
hash.c \
|
||||
lex.c \
|
||||
lib.c \
|
||||
mathlib.c \
|
||||
iolib.c \
|
||||
iolib.h \
|
||||
bitslib.c \
|
||||
misc.c \
|
||||
nasal.h \
|
||||
parse.c parse.h \
|
||||
string.c \
|
||||
vector.c \
|
||||
thread-posix.c \
|
||||
thread-win32.c
|
||||
libsgnasal_a_SOURCES = bitslib.c code.c code.h codegen.c data.h gc.c \
|
||||
hash.c iolib.c iolib.h lex.c lib.c mathlib.c \
|
||||
misc.c naref.h nasal.h parse.c parse.h string.c \
|
||||
thread-posix.c thread-win32.c threadlib.c \
|
||||
utf8lib.c vector.c
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
+10
-17
@@ -5,10 +5,10 @@
|
||||
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch
|
||||
// that beyond what is representable in the double result, but
|
||||
// requires portability work.
|
||||
|
||||
#define BIT(s,l,n) s[l-1-((n)>>3)] & (1<<((n)&7))
|
||||
#define CLRB(s,l,n) s[l-1-((n)>>3)] &= ~(1<<((n)&7))
|
||||
#define SETB(s,l,n) s[l-1-((n)>>3)] |= 1<<((n)&7)
|
||||
#define MSK(n) (1 << (7 - ((n) & 7)))
|
||||
#define BIT(s,l,n) s[(n)>>3] & MSK(n)
|
||||
#define CLRB(s,l,n) s[(n)>>3] &= ~MSK(n)
|
||||
#define SETB(s,l,n) s[(n)>>3] |= MSK(n)
|
||||
|
||||
static unsigned int fld(naContext c, unsigned char* s,
|
||||
int slen, int bit, int flen)
|
||||
@@ -32,7 +32,7 @@ static void setfld(naContext c, unsigned char* s, int slen,
|
||||
|
||||
static naRef dofld(naContext c, int argc, naRef* args, int sign)
|
||||
{
|
||||
struct naStr* s = argc > 0 ? args[0].ref.ptr.str : 0;
|
||||
struct naStr* s = argc > 0 ? PTR(args[0]).str : 0;
|
||||
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
||||
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
||||
unsigned int f;
|
||||
@@ -56,7 +56,7 @@ static naRef f_fld(naContext c, naRef me, int argc, naRef* args)
|
||||
|
||||
static naRef f_setfld(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
struct naStr* s = argc > 0 ? args[0].ref.ptr.str : 0;
|
||||
struct naStr* s = argc > 0 ? PTR(args[0]).str : 0;
|
||||
int bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
||||
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
||||
naRef val = argc > 3 ? naNumValue(args[3]) : naNil();
|
||||
@@ -73,22 +73,15 @@ static naRef f_buf(naContext c, naRef me, int argc, naRef* args)
|
||||
return naStr_buf(naNewString(c), (int)len.num);
|
||||
}
|
||||
|
||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "sfld", f_sfld },
|
||||
{ "fld", f_fld },
|
||||
{ "setfld", f_setfld },
|
||||
{ "buf", f_buf },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naBitsLib(naContext c)
|
||||
naRef naInit_bits(naContext c)
|
||||
{
|
||||
naRef namespace = naNewHash(c);
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++) {
|
||||
naRef code = naNewCCode(c, funcs[i].func);
|
||||
naRef name = naStr_fromdata(naNewString(c),
|
||||
funcs[i].name, strlen(funcs[i].name));
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
return namespace;
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
|
||||
+251
-160
@@ -1,11 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "nasal.h"
|
||||
#include "code.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Debugging stuff. ////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//#define DEBUG_NASAL
|
||||
#if !defined(DEBUG_NASAL)
|
||||
//#define INTERPRETER_DUMP
|
||||
#if !defined(INTERPRETER_DUMP)
|
||||
# define DBG(expr) /* noop */
|
||||
#else
|
||||
# define DBG(expr) expr
|
||||
@@ -17,21 +20,44 @@ void printOpDEBUG(int ip, int op);
|
||||
void printStackDEBUG(struct Context* ctx);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
struct Globals* globals = 0;
|
||||
|
||||
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
|
||||
|
||||
#define ERR(c, msg) naRuntimeError((c),(msg))
|
||||
void naRuntimeError(struct Context* c, char* msg)
|
||||
{
|
||||
c->error = msg;
|
||||
void naRuntimeError(struct Context* c, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(c->error, sizeof(c->error), fmt, ap);
|
||||
va_end(ap);
|
||||
longjmp(c->jumpHandle, 1);
|
||||
}
|
||||
|
||||
void naRethrowError(naContext subc)
|
||||
{
|
||||
strncpy(subc->callParent->error, subc->error, sizeof(subc->error));
|
||||
subc->callParent->dieArg = subc->dieArg;
|
||||
longjmp(subc->callParent->jumpHandle, 1);
|
||||
}
|
||||
|
||||
#define END_PTR ((void*)1)
|
||||
#define IS_END(r) (IS_REF((r)) && PTR((r)).obj == END_PTR)
|
||||
static naRef endToken()
|
||||
{
|
||||
naRef r;
|
||||
SETPTR(r, END_PTR);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int boolify(struct Context* ctx, naRef r)
|
||||
{
|
||||
if(IS_NUM(r)) return r.num != 0;
|
||||
if(IS_NIL(r)) return 0;
|
||||
if(IS_NIL(r) || IS_END(r)) return 0;
|
||||
if(IS_STR(r)) {
|
||||
double d;
|
||||
if(naStr_len(r) == 0) return 0;
|
||||
@@ -65,7 +91,9 @@ static int checkVec(struct Context* ctx, naRef vec, naRef idx)
|
||||
{
|
||||
int i = (int)numify(ctx, idx);
|
||||
if(i < 0) i += naVec_size(vec);
|
||||
if(i < 0 || i >= naVec_size(vec)) ERR(ctx, "vector index out of bounds");
|
||||
if(i < 0 || i >= naVec_size(vec))
|
||||
naRuntimeError(ctx, "vector index %d out of bounds (size: %d)",
|
||||
i, naVec_size(vec));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -73,7 +101,9 @@ static int checkStr(struct Context* ctx, naRef str, naRef idx)
|
||||
{
|
||||
int i = (int)numify(ctx, idx);
|
||||
if(i < 0) i += naStr_len(str);
|
||||
if(i < 0 || i >= naStr_len(str)) ERR(ctx, "string index out of bounds");
|
||||
if(i < 0 || i >= naStr_len(str))
|
||||
naRuntimeError(ctx, "string index %d out of bounds (size: %d)",
|
||||
i, naStr_len(str));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -82,8 +112,7 @@ static naRef containerGet(struct Context* ctx, naRef box, naRef key)
|
||||
naRef result = naNil();
|
||||
if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
|
||||
if(IS_HASH(box)) {
|
||||
if(!naHash_get(box, key, &result))
|
||||
ERR(ctx, "undefined value in container");
|
||||
naHash_get(box, key, &result);
|
||||
} else if(IS_VEC(box)) {
|
||||
result = naVec_get(box, checkVec(ctx, box, key));
|
||||
} else if(IS_STR(box)) {
|
||||
@@ -100,7 +129,7 @@ static void containerSet(struct Context* ctx, naRef box, naRef key, naRef val)
|
||||
else if(IS_HASH(box)) naHash_set(box, key, val);
|
||||
else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
|
||||
else if(IS_STR(box)) {
|
||||
if(box.ref.ptr.str->hashcode)
|
||||
if(PTR(box).str->hashcode)
|
||||
ERR(ctx, "cannot change immutable string");
|
||||
naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
|
||||
} else ERR(ctx, "insert into non-container");
|
||||
@@ -128,7 +157,8 @@ static void initContext(struct Context* c)
|
||||
c->callParent = 0;
|
||||
c->callChild = 0;
|
||||
c->dieArg = naNil();
|
||||
c->error = 0;
|
||||
c->error[0] = 0;
|
||||
c->userData = 0;
|
||||
}
|
||||
|
||||
static void initGlobals()
|
||||
@@ -191,47 +221,46 @@ struct Context* naNewContext()
|
||||
return c;
|
||||
}
|
||||
|
||||
struct Context* naSubContext(struct Context* super)
|
||||
{
|
||||
struct Context* ctx = naNewContext();
|
||||
if(super->callChild) naFreeContext(super->callChild);
|
||||
ctx->callParent = super;
|
||||
super->callChild = ctx;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void naFreeContext(struct Context* c)
|
||||
{
|
||||
c->ntemps = 0;
|
||||
if(c->callChild) naFreeContext(c->callChild);
|
||||
if(c->callParent) c->callParent->callChild = 0;
|
||||
LOCK();
|
||||
c->nextFree = globals->freeContexts;
|
||||
globals->freeContexts = c;
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is the original code which might not work properly on all
|
||||
* platforms since it allows one to work on the same variable in one
|
||||
* statement without the prior knowledge how this will behave.
|
||||
*
|
||||
* e.g. ctx->opStack[ctx->opTop++] = ctx->opStack[ctx->opTop-1];
|
||||
* ^^^^^ ^^^^^
|
||||
*/
|
||||
# define PUSH(r) do { \
|
||||
// Note that opTop is incremented separately, to avoid situations
|
||||
// where the "r" expression also references opTop. The SGI compiler
|
||||
// is known to have issues with such code.
|
||||
#define PUSH(r) do { \
|
||||
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \
|
||||
ctx->opStack[ctx->opTop++] = r; \
|
||||
ctx->opStack[ctx->opTop] = r; \
|
||||
ctx->opTop++; \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
# define PUSH(r) _PUSH((ctx), (r))
|
||||
void _PUSH(struct Context* ctx, naRef r) {
|
||||
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow");
|
||||
ctx->opStack[ctx->opTop++] = r;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||
{
|
||||
int i;
|
||||
struct naCode* c = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
struct naCode* c = PTR(PTR(f->func).func->code).code;
|
||||
|
||||
// Set the argument symbols, and put any remaining args in a vector
|
||||
if(nargs < c->nArgs) ERR(ctx, "not enough arguments to function call");
|
||||
if(nargs < c->nArgs)
|
||||
naRuntimeError(ctx, "too few function args (have %d need %d)",
|
||||
nargs, c->nArgs);
|
||||
for(i=0; i<c->nArgs; i++)
|
||||
naHash_newsym(f->locals.ref.ptr.hash,
|
||||
naHash_newsym(PTR(f->locals).hash,
|
||||
&c->constants[c->argSyms[i]], &args[i]);
|
||||
args += c->nArgs;
|
||||
nargs -= c->nArgs;
|
||||
@@ -239,7 +268,7 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||
naRef val = nargs > 0 ? args[i] : c->constants[c->optArgVals[i]];
|
||||
if(IS_CODE(val))
|
||||
val = bindFunction(ctx, &ctx->fStack[ctx->fTop-2], val);
|
||||
naHash_newsym(f->locals.ref.ptr.hash, &c->constants[c->optArgSyms[i]],
|
||||
naHash_newsym(PTR(f->locals).hash, &c->constants[c->optArgSyms[i]],
|
||||
&val);
|
||||
}
|
||||
args += c->nOptArgs;
|
||||
@@ -247,12 +276,12 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||
naRef argsv = naNewVector(ctx);
|
||||
naVec_setsize(argsv, nargs > 0 ? nargs : 0);
|
||||
for(i=0; i<nargs; i++)
|
||||
argsv.ref.ptr.vec->rec->array[i] = *args++;
|
||||
naHash_newsym(f->locals.ref.ptr.hash, &c->restArgSym, &argsv);
|
||||
PTR(argsv).vec->rec->array[i] = *args++;
|
||||
naHash_newsym(PTR(f->locals).hash, &c->restArgSym, &argsv);
|
||||
}
|
||||
}
|
||||
|
||||
struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
static struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall)
|
||||
{
|
||||
naRef *frame;
|
||||
struct Frame* f;
|
||||
@@ -263,20 +292,20 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
if(!IS_FUNC(frame[0]))
|
||||
ERR(ctx, "function/method call invoked on uncallable object");
|
||||
|
||||
// Just do native calls right here, and don't touch the stack
|
||||
// frames; return the current one (unless it's a tail call!).
|
||||
if(frame[0].ref.ptr.func->code.ref.ptr.obj->type == T_CCODE) {
|
||||
ctx->opFrame = ctx->opTop - (nargs + 1 + mcall);
|
||||
|
||||
// Just do native calls right here
|
||||
if(PTR(PTR(frame[0]).func->code).obj->type == T_CCODE) {
|
||||
naRef obj = mcall ? frame[-1] : naNil();
|
||||
naCFunction fp = frame[0].ref.ptr.func->code.ref.ptr.ccode->fptr;
|
||||
naCFunction fp = PTR(PTR(frame[0]).func->code).ccode->fptr;
|
||||
naRef result = (*fp)(ctx, obj, nargs, frame + 1);
|
||||
ctx->opTop -= nargs + 1 + mcall;
|
||||
ctx->opTop = ctx->opFrame;
|
||||
PUSH(result);
|
||||
return &(ctx->fStack[ctx->fTop-1]);
|
||||
}
|
||||
|
||||
if(tail) ctx->fTop--;
|
||||
else if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
|
||||
|
||||
if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
|
||||
|
||||
// Note: assign nil first, otherwise the naNew() can cause a GC,
|
||||
// which will now (after fTop++) see the *old* reference as a
|
||||
// markable value!
|
||||
@@ -285,7 +314,7 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
f->locals = naNewHash(ctx);
|
||||
f->func = frame[0];
|
||||
f->ip = 0;
|
||||
f->bp = ctx->opTop - (nargs + 1 + mcall);
|
||||
f->bp = ctx->opFrame;
|
||||
|
||||
if(mcall)
|
||||
naHash_set(f->locals, globals->meRef, frame[-1]);
|
||||
@@ -297,29 +326,35 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
||||
return f;
|
||||
}
|
||||
|
||||
static naRef evalAndOr(struct Context* ctx, int op, naRef ra, naRef rb)
|
||||
{
|
||||
int a = boolify(ctx, ra);
|
||||
int b = boolify(ctx, rb);
|
||||
int result;
|
||||
if(op == OP_AND) result = a && b ? 1 : 0;
|
||||
else result = a || b ? 1 : 0;
|
||||
return naNum(result);
|
||||
}
|
||||
|
||||
static naRef evalEquality(int op, naRef ra, naRef rb)
|
||||
{
|
||||
int result = naEqual(ra, rb);
|
||||
return naNum((op==OP_EQ) ? result : !result);
|
||||
}
|
||||
|
||||
static naRef evalCat(naContext ctx, naRef l, naRef r)
|
||||
{
|
||||
if(IS_VEC(l) && IS_VEC(r)) {
|
||||
int i, ls = naVec_size(l), rs = naVec_size(r);
|
||||
naRef v = naNewVector(ctx);
|
||||
naVec_setsize(v, ls + rs);
|
||||
for(i=0; i<ls; i+=1) naVec_set(v, i, naVec_get(l, i));
|
||||
for(i=0; i<rs; i+=1) naVec_set(v, i+ls, naVec_get(r, i));
|
||||
return v;
|
||||
} else {
|
||||
naRef a = stringify(ctx, l);
|
||||
naRef b = stringify(ctx, r);
|
||||
return naStr_concat(naNewString(ctx), a, b);
|
||||
}
|
||||
}
|
||||
|
||||
// When a code object comes out of the constant pool and shows up on
|
||||
// the stack, it needs to be bound with the lexical context.
|
||||
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
|
||||
{
|
||||
naRef result = naNewFunc(ctx, code);
|
||||
result.ref.ptr.func->namespace = f->locals;
|
||||
result.ref.ptr.func->next = f->func;
|
||||
PTR(result).func->namespace = f->locals;
|
||||
PTR(result).func->next = f->func;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -327,7 +362,7 @@ static int getClosure(struct naFunc* c, naRef sym, naRef* result)
|
||||
{
|
||||
while(c) {
|
||||
if(naHash_get(c->namespace, sym, result)) return 1;
|
||||
c = c->next.ref.ptr.func;
|
||||
c = PTR(c->next).func;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -336,8 +371,8 @@ static naRef getLocal2(struct Context* ctx, struct Frame* f, naRef sym)
|
||||
{
|
||||
naRef result;
|
||||
if(!naHash_get(f->locals, sym, &result))
|
||||
if(!getClosure(f->func.ref.ptr.func, sym, &result))
|
||||
ERR(ctx, "undefined symbol");
|
||||
if(!getClosure(PTR(f->func).func, sym, &result))
|
||||
naRuntimeError(ctx, "undefined symbol: %s", naStr_data(sym));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -345,14 +380,14 @@ static void getLocal(struct Context* ctx, struct Frame* f,
|
||||
naRef* sym, naRef* out)
|
||||
{
|
||||
struct naFunc* func;
|
||||
struct naStr* str = sym->ref.ptr.str;
|
||||
if(naHash_sym(f->locals.ref.ptr.hash, str, out))
|
||||
struct naStr* str = PTR(*sym).str;
|
||||
if(naHash_sym(PTR(f->locals).hash, str, out))
|
||||
return;
|
||||
func = f->func.ref.ptr.func;
|
||||
while(func && func->namespace.ref.ptr.hash) {
|
||||
if(naHash_sym(func->namespace.ref.ptr.hash, str, out))
|
||||
func = PTR(f->func).func;
|
||||
while(func && PTR(func->namespace).hash) {
|
||||
if(naHash_sym(PTR(func->namespace).hash, str, out))
|
||||
return;
|
||||
func = func->next.ref.ptr.func;
|
||||
func = PTR(func->next).func;
|
||||
}
|
||||
// Now do it again using the more general naHash_get(). This will
|
||||
// only be necessary if something has created the value in the
|
||||
@@ -363,7 +398,7 @@ static void getLocal(struct Context* ctx, struct Frame* f,
|
||||
|
||||
static int setClosure(naRef func, naRef sym, naRef val)
|
||||
{
|
||||
struct naFunc* c = func.ref.ptr.func;
|
||||
struct naFunc* c = PTR(func).func;
|
||||
if(c == 0) { return 0; }
|
||||
else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
|
||||
else { return setClosure(c->next, sym, val); }
|
||||
@@ -379,39 +414,52 @@ static naRef setSymbol(struct Frame* f, naRef sym, naRef val)
|
||||
return val;
|
||||
}
|
||||
|
||||
// Recursively descend into the parents lists
|
||||
static int getMember(struct Context* ctx, naRef obj, naRef fld,
|
||||
naRef* result, int count)
|
||||
// Funky API: returns null to indicate no member, an empty string to
|
||||
// indicate success, or a non-empty error message. Works this way so
|
||||
// we can generate smart error messages without throwing them with a
|
||||
// longjmp -- this gets called under naMember_get() from C code.
|
||||
static const char* getMember_r(naRef obj, naRef field, naRef* out, int count)
|
||||
{
|
||||
int i;
|
||||
naRef p;
|
||||
if(--count < 0) ERR(ctx, "too many parents");
|
||||
if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members");
|
||||
if(naHash_get(obj, fld, result)) {
|
||||
return 1;
|
||||
} else if(naHash_get(obj, globals->parentsRef, &p)) {
|
||||
if(IS_VEC(p)) {
|
||||
int i;
|
||||
struct VecRec* v = p.ref.ptr.vec->rec;
|
||||
for(i=0; i<v->size; i++)
|
||||
if(getMember(ctx, v->array[i], fld, result, count))
|
||||
return 1;
|
||||
} else
|
||||
ERR(ctx, "parents field not vector");
|
||||
struct VecRec* pv;
|
||||
if(--count < 0) return "too many parents";
|
||||
if(!IS_HASH(obj)) return 0;
|
||||
if(naHash_get(obj, field, out)) return "";
|
||||
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
|
||||
if(!IS_VEC(p)) return "object \"parents\" field not vector";
|
||||
pv = PTR(p).vec->rec;
|
||||
for(i=0; i<pv->size; i++) {
|
||||
const char* err = getMember_r(pv->array[i], field, out, count);
|
||||
if(err) return err; /* either an error or success */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void getMember(struct Context* ctx, naRef obj, naRef fld,
|
||||
naRef* result, int count)
|
||||
{
|
||||
const char* err = getMember_r(obj, fld, result, count);
|
||||
if(!err) naRuntimeError(ctx, "No such member: %s", naStr_data(fld));
|
||||
if(err[0]) naRuntimeError(ctx, err);
|
||||
}
|
||||
|
||||
int naMember_get(naRef obj, naRef field, naRef* out)
|
||||
{
|
||||
const char* err = getMember_r(obj, field, out, 64);
|
||||
return err && !err[0];
|
||||
}
|
||||
|
||||
// OP_EACH works like a vector get, except that it leaves the vector
|
||||
// and index on the stack, increments the index after use, and pops
|
||||
// the arguments and pushes a nil if the index is beyond the end.
|
||||
// and index on the stack, increments the index after use, and
|
||||
// pushes a nil if the index is beyond the end.
|
||||
static void evalEach(struct Context* ctx, int useIndex)
|
||||
{
|
||||
int idx = (int)(ctx->opStack[ctx->opTop-1].num);
|
||||
naRef vec = ctx->opStack[ctx->opTop-2];
|
||||
if(!IS_VEC(vec)) naRuntimeError(ctx, "foreach enumeration of non-vector");
|
||||
if(!vec.ref.ptr.vec->rec || idx >= vec.ref.ptr.vec->rec->size) {
|
||||
ctx->opTop -= 2; // pop two values
|
||||
PUSH(naNil());
|
||||
if(!IS_VEC(vec)) ERR(ctx, "foreach enumeration of non-vector");
|
||||
if(!PTR(vec).vec->rec || idx >= PTR(vec).vec->rec->size) {
|
||||
PUSH(endToken());
|
||||
return;
|
||||
}
|
||||
ctx->opStack[ctx->opTop-1].num = idx+1; // modify in place
|
||||
@@ -423,13 +471,16 @@ static void evalEach(struct Context* ctx, int useIndex)
|
||||
#define POP() ctx->opStack[--ctx->opTop]
|
||||
#define STK(n) (ctx->opStack[ctx->opTop-(n)])
|
||||
#define FIXFRAME() f = &(ctx->fStack[ctx->fTop-1]); \
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
cd = PTR(PTR(f->func).func->code).code;
|
||||
static naRef run(struct Context* ctx)
|
||||
{
|
||||
struct Frame* f;
|
||||
struct naCode* cd;
|
||||
int op, arg;
|
||||
naRef a, b, c;
|
||||
naRef a, b;
|
||||
|
||||
ctx->dieArg = naNil();
|
||||
ctx->error[0] = 0;
|
||||
|
||||
FIXFRAME();
|
||||
|
||||
@@ -455,8 +506,7 @@ static naRef run(struct Context* ctx)
|
||||
#define BINOP(expr) do { \
|
||||
double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \
|
||||
double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \
|
||||
STK(2).ref.reftag = ~NASAL_REFTAG; \
|
||||
STK(2).num = expr; \
|
||||
SETNUM(STK(2), expr); \
|
||||
ctx->opTop--; } while(0)
|
||||
|
||||
case OP_PLUS: BINOP(l + r); break;
|
||||
@@ -467,24 +517,15 @@ static naRef run(struct Context* ctx)
|
||||
case OP_LTE: BINOP(l <= r ? 1 : 0); break;
|
||||
case OP_GT: BINOP(l > r ? 1 : 0); break;
|
||||
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
|
||||
|
||||
#undef BINOP
|
||||
|
||||
case OP_EQ: case OP_NEQ:
|
||||
STK(2) = evalEquality(op, STK(2), STK(1));
|
||||
ctx->opTop--;
|
||||
break;
|
||||
case OP_AND: case OP_OR:
|
||||
STK(2) = evalAndOr(ctx, op, STK(2), STK(1));
|
||||
ctx->opTop--;
|
||||
break;
|
||||
case OP_CAT:
|
||||
// stringify can call the GC, so don't take stuff of the stack!
|
||||
a = stringify(ctx, ctx->opStack[ctx->opTop-1]);
|
||||
b = stringify(ctx, ctx->opStack[ctx->opTop-2]);
|
||||
c = naStr_concat(naNewString(ctx), b, a);
|
||||
ctx->opTop -= 2;
|
||||
PUSH(c);
|
||||
STK(2) = evalCat(ctx, STK(2), STK(1));
|
||||
ctx->opTop -= 1;
|
||||
break;
|
||||
case OP_NEG:
|
||||
STK(1) = naNum(-numify(ctx, STK(1)));
|
||||
@@ -506,6 +547,9 @@ static naRef run(struct Context* ctx)
|
||||
case OP_PUSHNIL:
|
||||
PUSH(naNil());
|
||||
break;
|
||||
case OP_PUSHEND:
|
||||
PUSH(endToken());
|
||||
break;
|
||||
case OP_NEWVEC:
|
||||
PUSH(naNewVector(ctx));
|
||||
break;
|
||||
@@ -535,8 +579,7 @@ static naRef run(struct Context* ctx)
|
||||
ctx->opTop--;
|
||||
break;
|
||||
case OP_MEMBER:
|
||||
if(!getMember(ctx, STK(1), CONSTARG(), &STK(1), 64))
|
||||
ERR(ctx, "no such member");
|
||||
getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
|
||||
break;
|
||||
case OP_SETMEMBER:
|
||||
if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members");
|
||||
@@ -563,15 +606,29 @@ static naRef run(struct Context* ctx)
|
||||
f->ip = cd->byteCode[f->ip];
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
break;
|
||||
case OP_JIFNIL:
|
||||
case OP_JIFEND:
|
||||
arg = ARG();
|
||||
if(IS_NIL(STK(1))) {
|
||||
if(IS_END(STK(1))) {
|
||||
ctx->opTop--; // Pops **ONLY** if it's nil!
|
||||
f->ip = arg;
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
}
|
||||
break;
|
||||
case OP_JIFTRUE:
|
||||
arg = ARG();
|
||||
if(boolify(ctx, STK(1))) {
|
||||
f->ip = arg;
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
}
|
||||
break;
|
||||
case OP_JIFNOT:
|
||||
arg = ARG();
|
||||
if(!boolify(ctx, STK(1))) {
|
||||
f->ip = arg;
|
||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||
}
|
||||
break;
|
||||
case OP_JIFNOTPOP:
|
||||
arg = ARG();
|
||||
if(!boolify(ctx, POP())) {
|
||||
f->ip = arg;
|
||||
@@ -579,23 +636,17 @@ static naRef run(struct Context* ctx)
|
||||
}
|
||||
break;
|
||||
case OP_FCALL:
|
||||
f = setupFuncall(ctx, ARG(), 0, 0);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
break;
|
||||
case OP_FTAIL:
|
||||
f = setupFuncall(ctx, ARG(), 0, 1);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
f = setupFuncall(ctx, ARG(), 0);
|
||||
cd = PTR(PTR(f->func).func->code).code;
|
||||
break;
|
||||
case OP_MCALL:
|
||||
f = setupFuncall(ctx, ARG(), 1, 0);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
break;
|
||||
case OP_MTAIL:
|
||||
f = setupFuncall(ctx, ARG(), 1, 1);
|
||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
||||
f = setupFuncall(ctx, ARG(), 1);
|
||||
cd = PTR(PTR(f->func).func->code).code;
|
||||
break;
|
||||
case OP_RETURN:
|
||||
a = STK(1);
|
||||
ctx->dieArg = naNil();
|
||||
if(ctx->callChild) naFreeContext(ctx->callChild);
|
||||
if(--ctx->fTop <= 0) return a;
|
||||
ctx->opTop = f->bp + 1; // restore the correct opstack frame!
|
||||
STK(1) = a;
|
||||
@@ -609,13 +660,16 @@ static naRef run(struct Context* ctx)
|
||||
break;
|
||||
case OP_MARK: // save stack state (e.g. "setjmp")
|
||||
if(ctx->markTop >= MAX_MARK_DEPTH)
|
||||
naRuntimeError(ctx, "mark stack overflow");
|
||||
ERR(ctx, "mark stack overflow");
|
||||
ctx->markStack[ctx->markTop++] = ctx->opTop;
|
||||
break;
|
||||
case OP_UNMARK: // pop stack state set by mark
|
||||
ctx->markTop--;
|
||||
break;
|
||||
case OP_BREAK: // restore stack state (FOLLOW WITH JMP!)
|
||||
ctx->opTop = ctx->markStack[ctx->markTop-1];
|
||||
break;
|
||||
case OP_BREAK2: // same, but also pop the mark stack
|
||||
ctx->opTop = ctx->markStack[--ctx->markTop];
|
||||
break;
|
||||
default:
|
||||
@@ -636,48 +690,55 @@ void naSave(struct Context* ctx, naRef obj)
|
||||
naVec_append(globals->save, obj);
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent
|
||||
int naStackDepth(struct Context* ctx)
|
||||
{
|
||||
return ctx->fTop;
|
||||
return ctx ? ctx->fTop + naStackDepth(ctx->callChild): 0;
|
||||
}
|
||||
|
||||
static int findFrame(naContext ctx, naContext* out, int fn)
|
||||
{
|
||||
int sd = naStackDepth(ctx->callChild);
|
||||
if(fn < sd) return findFrame(ctx->callChild, out, fn);
|
||||
*out = ctx;
|
||||
return ctx->fTop - 1 - (fn - sd);
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent
|
||||
int naGetLine(struct Context* ctx, int frame)
|
||||
{
|
||||
struct Frame* f = &ctx->fStack[ctx->fTop-1-frame];
|
||||
naRef func = f->func;
|
||||
int ip = f->ip;
|
||||
if(IS_FUNC(func) && IS_CODE(func.ref.ptr.func->code)) {
|
||||
struct naCode* c = func.ref.ptr.func->code.ref.ptr.code;
|
||||
struct Frame* f;
|
||||
frame = findFrame(ctx, &ctx, frame);
|
||||
f = &ctx->fStack[frame];
|
||||
if(IS_FUNC(f->func) && IS_CODE(PTR(f->func).func->code)) {
|
||||
struct naCode* c = PTR(PTR(f->func).func->code).code;
|
||||
unsigned short* p = c->lineIps + c->nLines - 2;
|
||||
while(p >= c->lineIps && p[0] > ip)
|
||||
while(p >= c->lineIps && p[0] > f->ip)
|
||||
p -= 2;
|
||||
return p[1];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent
|
||||
naRef naGetSourceFile(struct Context* ctx, int frame)
|
||||
{
|
||||
naRef f = ctx->fStack[ctx->fTop-1-frame].func;
|
||||
f = f.ref.ptr.func->code;
|
||||
return f.ref.ptr.code->srcFile;
|
||||
naRef f;
|
||||
frame = findFrame(ctx, &ctx, frame);
|
||||
f = ctx->fStack[frame].func;
|
||||
f = PTR(f).func->code;
|
||||
return PTR(f).code->srcFile;
|
||||
}
|
||||
|
||||
char* naGetError(struct Context* ctx)
|
||||
{
|
||||
if(IS_STR(ctx->dieArg))
|
||||
return (char*)ctx->dieArg.ref.ptr.str->data;
|
||||
return ctx->error;
|
||||
return (char*)PTR(ctx->dieArg).str->data;
|
||||
return ctx->error[0] ? ctx->error : 0;
|
||||
}
|
||||
|
||||
naRef naBindFunction(naContext ctx, naRef code, naRef closure)
|
||||
{
|
||||
naRef func = naNewFunc(ctx, code);
|
||||
func.ref.ptr.func->namespace = closure;
|
||||
func.ref.ptr.func->next = naNil();
|
||||
PTR(func).func->namespace = closure;
|
||||
PTR(func).func->next = naNil();
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -685,8 +746,8 @@ naRef naBindToContext(naContext ctx, naRef code)
|
||||
{
|
||||
naRef func = naNewFunc(ctx, code);
|
||||
struct Frame* f = &ctx->fStack[ctx->fTop-1];
|
||||
func.ref.ptr.func->namespace = f->locals;
|
||||
func.ref.ptr.func->next = f->func;
|
||||
PTR(func).func->namespace = f->locals;
|
||||
PTR(func).func->next = f->func;
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -695,7 +756,7 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
{
|
||||
int i;
|
||||
naRef result;
|
||||
if(!ctx->callParent) naModLock(ctx);
|
||||
if(!ctx->callParent) naModLock();
|
||||
|
||||
// We might have to allocate objects, which can call the GC. But
|
||||
// the call isn't on the Nasal stack yet, so the GC won't find our
|
||||
@@ -706,22 +767,28 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
naTempSave(ctx, obj);
|
||||
naTempSave(ctx, locals);
|
||||
|
||||
if(IS_CCODE(func.ref.ptr.func->code)) {
|
||||
naCFunction fp = func.ref.ptr.func->code.ref.ptr.ccode->fptr;
|
||||
result = (*fp)(ctx, obj, argc, args);
|
||||
// naRuntimeError() calls end up here:
|
||||
if(setjmp(ctx->jumpHandle)) {
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
if(IS_CCODE(PTR(func).func->code)) {
|
||||
naCFunction fp = PTR(PTR(func).func->code).ccode->fptr;
|
||||
result = (*fp)(ctx, obj, argc, args);
|
||||
if(!ctx->callParent) naModUnlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
if(IS_NIL(locals))
|
||||
locals = naNewHash(ctx);
|
||||
if(!IS_FUNC(func))
|
||||
func = naNewFunc(ctx, func); // bind bare code objects
|
||||
if(!IS_FUNC(func)) {
|
||||
func = naNewFunc(ctx, func);
|
||||
PTR(func).func->namespace = locals;
|
||||
}
|
||||
if(!IS_NIL(obj))
|
||||
naHash_set(locals, globals->meRef, obj);
|
||||
|
||||
ctx->dieArg = naNil();
|
||||
|
||||
ctx->opTop = ctx->markTop = 0;
|
||||
ctx->fTop = 1;
|
||||
ctx->fStack[0].func = func;
|
||||
@@ -729,18 +796,42 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
ctx->fStack[0].ip = 0;
|
||||
ctx->fStack[0].bp = ctx->opTop;
|
||||
|
||||
setupArgs(ctx, ctx->fStack, args, argc);
|
||||
|
||||
// Return early if an error occurred. It will be visible to the
|
||||
// caller via naGetError().
|
||||
ctx->error = 0;
|
||||
if(setjmp(ctx->jumpHandle)) {
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
return naNil();
|
||||
}
|
||||
if(args) setupArgs(ctx, ctx->fStack, args, argc);
|
||||
|
||||
result = run(ctx);
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
naRef naContinue(naContext ctx)
|
||||
{
|
||||
naRef result;
|
||||
if(!ctx->callParent) naModLock();
|
||||
|
||||
ctx->dieArg = naNil();
|
||||
ctx->error[0] = 0;
|
||||
|
||||
if(setjmp(ctx->jumpHandle)) {
|
||||
if(!ctx->callParent) naModUnlock(ctx);
|
||||
else naRethrowError(ctx);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
// Wipe off the old function arguments, and push the expected
|
||||
// result (either the result of our subcontext, or a synthesized
|
||||
// nil if the thrown error was from an extension function or
|
||||
// in-script die() call) before re-running the code from the
|
||||
// instruction following the error.
|
||||
ctx->opTop = ctx->opFrame;
|
||||
PUSH(ctx->callChild ? naContinue(ctx->callChild) : naNil());
|
||||
|
||||
// Getting here means the child completed successfully. But
|
||||
// because its original C stack was longjmp'd out of existence,
|
||||
// there is no one left to free the context, so we have to do it.
|
||||
// This is fragile, but unfortunately required.
|
||||
if(ctx->callChild) naFreeContext(ctx->callChild);
|
||||
|
||||
result = run(ctx);
|
||||
if(!ctx->callParent) naModUnlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
+19
-10
@@ -10,19 +10,23 @@
|
||||
#define MAX_MARK_DEPTH 128
|
||||
|
||||
// Number of objects (per pool per thread) asked for using naGC_get().
|
||||
// Testing with fib.nas shows that this gives the best performance,
|
||||
// without too much per-thread overhead.
|
||||
#define OBJ_CACHE_SZ 128
|
||||
// The idea is that contexts can "cache" allocations to prevent thread
|
||||
// contention on the global pools. But in practice this interacts
|
||||
// very badly with small subcontext calls, which grab huge numbers of
|
||||
// cached objects and don't use them, causing far more collections
|
||||
// than necessary. Just leave it at 1 pending a rework of the
|
||||
// collector synchronization.
|
||||
#define OBJ_CACHE_SZ 1
|
||||
|
||||
enum {
|
||||
OP_AND, OP_OR, OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG,
|
||||
OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG,
|
||||
OP_CAT, OP_LT, OP_LTE, OP_GT, OP_GTE, OP_EQ, OP_NEQ, OP_EACH,
|
||||
OP_JMP, OP_JMPLOOP, OP_JIFNOT, OP_JIFNIL, OP_FCALL, OP_MCALL, OP_RETURN,
|
||||
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
|
||||
OP_JMP, OP_JMPLOOP, OP_JIFNOTPOP, OP_JIFEND, OP_FCALL, OP_MCALL,
|
||||
OP_RETURN, OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
|
||||
OP_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
|
||||
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
|
||||
OP_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2,
|
||||
OP_INDEX
|
||||
OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2, OP_INDEX, OP_BREAK2,
|
||||
OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
@@ -69,6 +73,7 @@ struct Context {
|
||||
struct Frame fStack[MAX_RECURSION];
|
||||
int fTop;
|
||||
naRef opStack[MAX_STACK_DEPTH];
|
||||
int opFrame; // like Frame::bp, but for C functions
|
||||
int opTop;
|
||||
int markStack[MAX_MARK_DEPTH];
|
||||
int markTop;
|
||||
@@ -86,7 +91,7 @@ struct Context {
|
||||
|
||||
// Error handling
|
||||
jmp_buf jumpHandle;
|
||||
char* error;
|
||||
char error[128];
|
||||
naRef dieArg;
|
||||
|
||||
// Sub-call lists
|
||||
@@ -96,6 +101,8 @@ struct Context {
|
||||
// Linked list pointers in globals
|
||||
struct Context* nextFree;
|
||||
struct Context* nextAll;
|
||||
|
||||
void* userData;
|
||||
};
|
||||
|
||||
#define globals nasal_globals
|
||||
@@ -103,11 +110,13 @@ extern struct Globals* globals;
|
||||
|
||||
// Threading low-level functions
|
||||
void* naNewLock();
|
||||
void naFreeLock(void* lock);
|
||||
void naLock(void* lock);
|
||||
void naUnlock(void* lock);
|
||||
void* naNewSem();
|
||||
void naFreeSem(void* sem);
|
||||
void naSemDown(void* sem);
|
||||
void naSemUpAll(void* sem, int count);
|
||||
void naSemUp(void* sem, int count);
|
||||
|
||||
void naCheckBottleneck();
|
||||
|
||||
|
||||
+29
-56
@@ -91,41 +91,6 @@ static int findConstantIndex(struct Parser* p, struct Token* t)
|
||||
return internConstant(p, c);
|
||||
}
|
||||
|
||||
static int lastExprInBlock(struct Token* t)
|
||||
{
|
||||
if(!t->parent) return 1;
|
||||
if(t->parent->type == TOK_TOP || t->parent->type == TOK_LCURL) return 1;
|
||||
if(t->parent->type == TOK_SEMI)
|
||||
if(!t->next || t->next->type == TOK_EMPTY)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns true if the node is in "tail context" -- either a child of
|
||||
// a return, the last child of a func block, or else the
|
||||
// last child of an if/elsif/if that is itself in tail context.
|
||||
static int tailContext(struct Token* t)
|
||||
{
|
||||
if(t->parent && t->parent->type == TOK_RETURN)
|
||||
return 1;
|
||||
else if(!lastExprInBlock(t))
|
||||
return 0;
|
||||
|
||||
// Walk up the tree. It is ok to see semicolons, else's, elsifs
|
||||
// and curlies. If we reach the top or a func, then we are in
|
||||
// tail context. If we hit an if, then we are in tail context
|
||||
// only if the "if" node is.
|
||||
while((t = t->parent) != 0)
|
||||
switch(t->type) {
|
||||
case TOK_SEMI: case TOK_LCURL: break;
|
||||
case TOK_ELSE: case TOK_ELSIF: break;
|
||||
case TOK_TOP: case TOK_FUNC: return 1;
|
||||
case TOK_IF: return tailContext(t);
|
||||
default: return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genScalarConstant(struct Parser* p, struct Token* t)
|
||||
{
|
||||
// These opcodes are for special-case use in other constructs, but
|
||||
@@ -145,7 +110,7 @@ static int genScalarConstant(struct Parser* p, struct Token* t)
|
||||
|
||||
static int genLValue(struct Parser* p, struct Token* t, int* cidx)
|
||||
{
|
||||
if(t->type == TOK_LPAR) {
|
||||
if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) {
|
||||
return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
|
||||
} else if(t->type == TOK_SYMBOL) {
|
||||
*cidx = genScalarConstant(p, t);
|
||||
@@ -187,6 +152,15 @@ static void genEqOp(int op, struct Parser* p, struct Token* t)
|
||||
static int defArg(struct Parser* p, struct Token* t)
|
||||
{
|
||||
if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
|
||||
if(t->type == TOK_MINUS && RIGHT(t) &&
|
||||
RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
|
||||
{
|
||||
/* default arguments are constants, but "-1" parses as two
|
||||
* tokens, so we have to subset the expression generator for that
|
||||
* case */
|
||||
RIGHT(t)->num *= -1;
|
||||
return defArg(p, RIGHT(t));
|
||||
}
|
||||
return findConstantIndex(p, t);
|
||||
}
|
||||
|
||||
@@ -293,8 +267,6 @@ static void genFuncall(struct Parser* p, struct Token* t)
|
||||
genExpr(p, LEFT(t));
|
||||
}
|
||||
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
|
||||
if(tailContext(t))
|
||||
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
|
||||
emitImmediate(p, op, nargs);
|
||||
}
|
||||
|
||||
@@ -334,15 +306,12 @@ static void fixJumpTarget(struct Parser* p, int spot)
|
||||
|
||||
static void genShortCircuit(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND);
|
||||
int end;
|
||||
genExpr(p, LEFT(t));
|
||||
if(isAnd) emit(p, OP_NOT);
|
||||
jumpNext = emitJump(p, OP_JIFNOT);
|
||||
emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE);
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
|
||||
emit(p, OP_POP);
|
||||
genExpr(p, RIGHT(t));
|
||||
fixJumpTarget(p, jumpEnd);
|
||||
fixJumpTarget(p, end);
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +319,7 @@ static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
|
||||
{
|
||||
int jumpNext, jumpEnd;
|
||||
genExpr(p, tif->children); // the test
|
||||
jumpNext = emitJump(p, OP_JIFNOT);
|
||||
jumpNext = emitJump(p, OP_JIFNOTPOP);
|
||||
genExprList(p, tif->children->next->children); // the body
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
@@ -374,7 +343,7 @@ static void genQuestion(struct Parser* p, struct Token* t)
|
||||
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
|
||||
naParseError(p, "invalid ?: expression", t->line);
|
||||
genExpr(p, LEFT(t)); // the test
|
||||
jumpNext = emitJump(p, OP_JIFNOT);
|
||||
jumpNext = emitJump(p, OP_JIFNOTPOP);
|
||||
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
|
||||
jumpEnd = emitJump(p, OP_JMP);
|
||||
fixJumpTarget(p, jumpNext);
|
||||
@@ -420,7 +389,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
|
||||
pushLoop(p, label);
|
||||
loopTop = p->cg->codesz;
|
||||
genExpr(p, test);
|
||||
jumpEnd = emitJump(p, OP_JIFNOT);
|
||||
jumpEnd = emitJump(p, OP_JIFNOTPOP);
|
||||
genLoop(p, body, update, label, loopTop, jumpEnd);
|
||||
}
|
||||
|
||||
@@ -480,17 +449,19 @@ static void genForEach(struct Parser* p, struct Token* t)
|
||||
vec = RIGHT(h);
|
||||
body = RIGHT(t)->children;
|
||||
|
||||
pushLoop(p, label);
|
||||
genExpr(p, vec);
|
||||
emit(p, OP_PUSHZERO);
|
||||
pushLoop(p, label);
|
||||
loopTop = p->cg->codesz;
|
||||
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
|
||||
jumpEnd = emitJump(p, OP_JIFNIL);
|
||||
jumpEnd = emitJump(p, OP_JIFEND);
|
||||
assignOp = genLValue(p, elem, &dummy);
|
||||
emit(p, OP_XCHG);
|
||||
emit(p, assignOp);
|
||||
emit(p, OP_POP);
|
||||
genLoop(p, body, 0, label, loopTop, jumpEnd);
|
||||
emit(p, OP_POP); // Pull off the vector and index
|
||||
emit(p, OP_POP);
|
||||
}
|
||||
|
||||
static int tokMatch(struct Token* a, struct Token* b)
|
||||
@@ -518,9 +489,9 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
|
||||
bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
|
||||
cp = p->cg->loops[p->cg->loopTop - levels].contIP;
|
||||
for(i=0; i<levels; i++)
|
||||
emit(p, OP_BREAK);
|
||||
emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
|
||||
if(t->type == TOK_BREAK)
|
||||
emit(p, OP_PUSHNIL); // breakIP is always a JIFNOT/JIFNIL!
|
||||
emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
|
||||
emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
|
||||
}
|
||||
|
||||
@@ -542,6 +513,8 @@ static void newLineEntry(struct Parser* p, int line)
|
||||
static void genExpr(struct Parser* p, struct Token* t)
|
||||
{
|
||||
int i, dummy;
|
||||
if(!t) naParseError(p, "parse error", -1); // throw line -1...
|
||||
p->errLine = t->line; // ...to use this one instead
|
||||
if(t->line != p->cg->lastLine)
|
||||
newLineEntry(p, t->line);
|
||||
p->cg->lastLine = t->line;
|
||||
@@ -611,7 +584,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
case TOK_MINUS:
|
||||
if(BINARY(t)) {
|
||||
genBinOp(OP_MINUS, p, t); // binary subtraction
|
||||
} else if(RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
|
||||
} else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
|
||||
RIGHT(t)->num *= -1; // Pre-negate constants
|
||||
genScalarConstant(p, RIGHT(t));
|
||||
} else {
|
||||
@@ -625,7 +598,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
break;
|
||||
case TOK_DOT:
|
||||
genExpr(p, LEFT(t));
|
||||
if(RIGHT(t)->type != TOK_SYMBOL)
|
||||
if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
|
||||
naParseError(p, "object field not symbol", RIGHT(t)->line);
|
||||
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
|
||||
break;
|
||||
@@ -656,7 +629,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
||||
|
||||
static void genExprList(struct Parser* p, struct Token* t)
|
||||
{
|
||||
if(t->type == TOK_SEMI) {
|
||||
if(t && t->type == TOK_SEMI) {
|
||||
genExpr(p, LEFT(t));
|
||||
if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
|
||||
emit(p, OP_POP);
|
||||
@@ -690,7 +663,7 @@ naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
|
||||
|
||||
// Now make a code object
|
||||
codeObj = naNewCode(p->context);
|
||||
code = codeObj.ref.ptr.code;
|
||||
code = PTR(codeObj).code;
|
||||
|
||||
// Parse the argument list, if any
|
||||
code->restArgSym = globals->argRef;
|
||||
|
||||
+72
-16
@@ -3,30 +3,86 @@
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
#if defined(NASAL_NAN64)
|
||||
|
||||
// On 64 bit systems, Nasal non-numeric references are stored with a
|
||||
// bitmask that sets the top 16 bits. As a double, this is a
|
||||
// signalling NaN that cannot itself be produced by normal numerics
|
||||
// code. The pointer value can be reconstructed if (and only if) we
|
||||
// are guaranteed that all memory that can be pointed to by a naRef
|
||||
// (i.e. all memory returned by naAlloc) lives in the bottom 48 bits
|
||||
// of memory. Linux on x86_64, Win64, Solaris and Irix all have such
|
||||
// policies with address spaces:
|
||||
//
|
||||
// http://msdn.microsoft.com/library/en-us/win64/win64/virtual_address_space.asp
|
||||
// http://docs.sun.com/app/docs/doc/816-5138/6mba6ua5p?a=view
|
||||
// http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/
|
||||
// ... 0650/bks/SGI_Developer/books/T_IRIX_Prog/sgi_html/ch01.html
|
||||
//
|
||||
// In the above, MS guarantees 44 bits of process address space, SGI
|
||||
// 40, and Sun 43 (Solaris *does* place the stack in the "negative"
|
||||
// address space at 0xffff..., but we don't care as naRefs will never
|
||||
// point there). Linux doesn't document this rigorously, but testing
|
||||
// shows that it allows 47 bits of address space (and current x86_64
|
||||
// implementations are limited to 48 bits of virtual space anyway). So
|
||||
// we choose 48 as the conservative compromise.
|
||||
|
||||
#define REFMAGIC ((1UL<<48) - 1)
|
||||
|
||||
#define _ULP(r) ((unsigned long long)((r).ptr))
|
||||
#define REFPTR(r) (_ULP(r) & REFMAGIC)
|
||||
#define IS_REF(r) ((_ULP(r) & ~REFMAGIC) == ~REFMAGIC)
|
||||
|
||||
// Portability note: this cast from a pointer type to naPtr (a union)
|
||||
// is not defined in ISO C, it's a GCC extention that doesn't work on
|
||||
// (at least) either the SUNWspro or MSVC compilers. Unfortunately,
|
||||
// fixing this would require abandoning the naPtr union for a set of
|
||||
// PTR_<type>() macros, which is a ton of work and a lot of extra
|
||||
// code. And as all enabled 64 bit platforms are gcc anyway, and the
|
||||
// 32 bit fallback code works in any case, this is acceptable for now.
|
||||
#define PTR(r) ((naPtr)((struct naObj*)(_ULP(r) & REFMAGIC)))
|
||||
|
||||
#define SETPTR(r, p) ((r).ptr = (void*)((unsigned long long)p | ~REFMAGIC))
|
||||
#define SETNUM(r, n) ((r).num = n)
|
||||
|
||||
#else
|
||||
|
||||
// On 32 bit systems where the pointer is half the width of the
|
||||
// double, we store a special magic number in the structure to make
|
||||
// the double a NaN. This must appear in the top bits of the double,
|
||||
// which is why the structure layout is endianness-dependent.
|
||||
|
||||
#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal
|
||||
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
|
||||
#define PTR(r) ((r).ref.ptr)
|
||||
|
||||
#define SETPTR(r, p) ((r).ref.ptr.obj = (void*)p, (r).ref.reftag = NASAL_REFTAG)
|
||||
#define SETNUM(r, n) ((r).ref.reftag = ~NASAL_REFTAG, (r).num = n)
|
||||
|
||||
#endif /* platform stuff */
|
||||
|
||||
enum { T_STR, T_VEC, T_HASH, T_CODE, T_FUNC, T_CCODE, T_GHOST,
|
||||
NUM_NASAL_TYPES }; // V. important that this come last!
|
||||
|
||||
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
|
||||
#define IS_NUM(r) ((r).ref.reftag != NASAL_REFTAG)
|
||||
#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0)
|
||||
//#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0 && (((r).ref.ptr.obj->type == 123) ? *(int*)0 : 1))
|
||||
#define IS_NIL(r) (IS_REF((r)) && (r).ref.ptr.obj == 0)
|
||||
#define IS_STR(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_STR)
|
||||
#define IS_VEC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_VEC)
|
||||
#define IS_HASH(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_HASH)
|
||||
#define IS_CODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CODE)
|
||||
#define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC)
|
||||
#define IS_CCODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CCODE)
|
||||
#define IS_GHOST(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_GHOST)
|
||||
#define IS_NUM(r) (!IS_REF(r))
|
||||
#define IS_OBJ(r) (IS_REF(r) && PTR(r).obj != 0)
|
||||
#define IS_NIL(r) (IS_REF(r) && PTR(r).obj == 0)
|
||||
#define IS_STR(r) (IS_OBJ(r) && PTR(r).obj->type == T_STR)
|
||||
#define IS_VEC(r) (IS_OBJ(r) && PTR(r).obj->type == T_VEC)
|
||||
#define IS_HASH(r) (IS_OBJ(r) && PTR(r).obj->type == T_HASH)
|
||||
#define IS_CODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CODE)
|
||||
#define IS_FUNC(r) (IS_OBJ(r) && PTR(r).obj->type == T_FUNC)
|
||||
#define IS_CCODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CCODE)
|
||||
#define IS_GHOST(r) (IS_OBJ(r) && PTR(r).obj->type == T_GHOST)
|
||||
#define IS_CONTAINER(r) (IS_VEC(r)||IS_HASH(r))
|
||||
#define IS_SCALAR(r) (IS_NUM((r)) || IS_STR((r)))
|
||||
#define IS_SCALAR(r) (IS_NUM(r) || IS_STR(r))
|
||||
#define IDENTICAL(a, b) (IS_REF(a) && IS_REF(b) \
|
||||
&& a.ref.ptr.obj == b.ref.ptr.obj)
|
||||
&& PTR(a).obj == PTR(b).obj)
|
||||
|
||||
#define MUTABLE(r) (IS_STR(r) && (r).ref.ptr.str->hashcode == 0)
|
||||
#define MUTABLE(r) (IS_STR(r) && PTR(r).str->hashcode == 0)
|
||||
|
||||
// This is a macro instead of a separate struct to allow compilers to
|
||||
// avoid padding. GCC on x86, at least, will always padd the size of
|
||||
// avoid padding. GCC on x86, at least, will always pad the size of
|
||||
// an embedded struct up to 32 bits. Doing it this way allows the
|
||||
// implementing objects to pack in 16 bits worth of data "for free".
|
||||
#define GC_HEADER \
|
||||
|
||||
+27
-37
@@ -2,7 +2,7 @@
|
||||
#include "data.h"
|
||||
#include "code.h"
|
||||
|
||||
#define MIN_BLOCK_SIZE 256
|
||||
#define MIN_BLOCK_SIZE 32
|
||||
|
||||
static void reap(struct naPool* p);
|
||||
static void mark(naRef r);
|
||||
@@ -27,7 +27,7 @@ static void marktemps(struct Context* c)
|
||||
int i;
|
||||
naRef r = naNil();
|
||||
for(i=0; i<c->ntemps; i++) {
|
||||
r.ref.ptr.obj = c->temps[i];
|
||||
SETPTR(r, c->temps[i]);
|
||||
mark(r);
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ static void bottleneck()
|
||||
if(g->waitCount >= g->nThreads - 1) {
|
||||
freeDead();
|
||||
if(g->needGC) garbageCollect();
|
||||
if(g->waitCount) naSemUpAll(g->sem, g->waitCount);
|
||||
if(g->waitCount) naSemUp(g->sem, g->waitCount);
|
||||
g->bottleneck = 0;
|
||||
}
|
||||
}
|
||||
@@ -130,34 +130,21 @@ static void naCode_gcclean(struct naCode* o)
|
||||
|
||||
static void naGhost_gcclean(struct naGhost* g)
|
||||
{
|
||||
if(g->ptr) g->gtype->destroy(g->ptr);
|
||||
if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr);
|
||||
g->ptr = 0;
|
||||
}
|
||||
|
||||
static void freeelem(struct naPool* p, struct naObj* o)
|
||||
{
|
||||
// Free any intrinsic (i.e. non-garbage collected) storage the
|
||||
// object might have
|
||||
// Clean up any intrinsic storage the object might have...
|
||||
switch(p->type) {
|
||||
case T_STR:
|
||||
naStr_gcclean((struct naStr*)o);
|
||||
break;
|
||||
case T_VEC:
|
||||
naVec_gcclean((struct naVec*)o);
|
||||
break;
|
||||
case T_HASH:
|
||||
naHash_gcclean((struct naHash*)o);
|
||||
break;
|
||||
case T_CODE:
|
||||
naCode_gcclean((struct naCode*)o);
|
||||
break;
|
||||
case T_GHOST:
|
||||
naGhost_gcclean((struct naGhost*)o);
|
||||
break;
|
||||
case T_STR: naStr_gcclean ((struct naStr*) o); break;
|
||||
case T_VEC: naVec_gcclean ((struct naVec*) o); break;
|
||||
case T_HASH: naHash_gcclean ((struct naHash*) o); break;
|
||||
case T_CODE: naCode_gcclean ((struct naCode*) o); break;
|
||||
case T_GHOST: naGhost_gcclean((struct naGhost*)o); break;
|
||||
}
|
||||
|
||||
// And add it to the free list
|
||||
p->free[p->nfree++] = o;
|
||||
p->free[p->nfree++] = o; // ...and add it to the free list
|
||||
}
|
||||
|
||||
static void newBlock(struct naPool* p, int need)
|
||||
@@ -227,7 +214,7 @@ struct naObj** naGC_get(struct naPool* p, int n, int* nout)
|
||||
static void markvec(naRef r)
|
||||
{
|
||||
int i;
|
||||
struct VecRec* vr = r.ref.ptr.vec->rec;
|
||||
struct VecRec* vr = PTR(r).vec->rec;
|
||||
if(!vr) return;
|
||||
for(i=0; i<vr->size; i++)
|
||||
mark(vr->array[i]);
|
||||
@@ -236,7 +223,7 @@ static void markvec(naRef r)
|
||||
static void markhash(naRef r)
|
||||
{
|
||||
int i;
|
||||
struct HashRec* hr = r.ref.ptr.hash->rec;
|
||||
struct HashRec* hr = PTR(r).hash->rec;
|
||||
if(!hr) return;
|
||||
for(i=0; i < (1<<hr->lgalloced); i++) {
|
||||
struct HashNode* hn = hr->table[i];
|
||||
@@ -257,22 +244,22 @@ static void mark(naRef r)
|
||||
if(IS_NUM(r) || IS_NIL(r))
|
||||
return;
|
||||
|
||||
if(r.ref.ptr.obj->mark == 1)
|
||||
if(PTR(r).obj->mark == 1)
|
||||
return;
|
||||
|
||||
r.ref.ptr.obj->mark = 1;
|
||||
switch(r.ref.ptr.obj->type) {
|
||||
PTR(r).obj->mark = 1;
|
||||
switch(PTR(r).obj->type) {
|
||||
case T_VEC: markvec(r); break;
|
||||
case T_HASH: markhash(r); break;
|
||||
case T_CODE:
|
||||
mark(r.ref.ptr.code->srcFile);
|
||||
for(i=0; i<r.ref.ptr.code->nConstants; i++)
|
||||
mark(r.ref.ptr.code->constants[i]);
|
||||
mark(PTR(r).code->srcFile);
|
||||
for(i=0; i<PTR(r).code->nConstants; i++)
|
||||
mark(PTR(r).code->constants[i]);
|
||||
break;
|
||||
case T_FUNC:
|
||||
mark(r.ref.ptr.func->code);
|
||||
mark(r.ref.ptr.func->namespace);
|
||||
mark(r.ref.ptr.func->next);
|
||||
mark(PTR(r).func->code);
|
||||
mark(PTR(r).func->namespace);
|
||||
mark(PTR(r).func->next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -283,7 +270,6 @@ static void reap(struct naPool* p)
|
||||
{
|
||||
struct Block* b;
|
||||
int elem, freesz, total = poolsize(p);
|
||||
p->nfree = 0;
|
||||
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
|
||||
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
|
||||
if(p->freesz < freesz) {
|
||||
@@ -292,6 +278,9 @@ static void reap(struct naPool* p)
|
||||
p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz);
|
||||
}
|
||||
|
||||
p->nfree = 0;
|
||||
p->free = p->free0;
|
||||
|
||||
for(b = p->blocks; b; b = b->next)
|
||||
for(elem=0; elem < b->size; elem++) {
|
||||
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
|
||||
@@ -300,6 +289,8 @@ static void reap(struct naPool* p)
|
||||
o->mark = 0;
|
||||
}
|
||||
|
||||
p->freetop = p->nfree;
|
||||
|
||||
// allocs of this type until the next collection
|
||||
globals->allocCount += total/2;
|
||||
|
||||
@@ -312,7 +303,6 @@ static void reap(struct naPool* p)
|
||||
if(need > 0)
|
||||
newBlock(p, need);
|
||||
}
|
||||
p->freetop = p->nfree;
|
||||
}
|
||||
|
||||
// Does the swap, returning the old value
|
||||
|
||||
+35
-30
@@ -3,9 +3,7 @@
|
||||
|
||||
#define MIN_HASH_SIZE 4
|
||||
|
||||
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \
|
||||
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|
||||
|| naEqual(a, b))
|
||||
#define EQUAL(a, b) (IDENTICAL(a, b) || naEqual(a, b))
|
||||
|
||||
#define HASH_MAGIC 2654435769u
|
||||
|
||||
@@ -28,15 +26,15 @@ static unsigned int hashcode(naRef r)
|
||||
// 2*sizeof(int).
|
||||
unsigned int* p = (unsigned int*)&(r.num);
|
||||
return p[0] ^ p[1];
|
||||
} else if(r.ref.ptr.str->hashcode) {
|
||||
return r.ref.ptr.str->hashcode;
|
||||
} else if(PTR(r).str->hashcode) {
|
||||
return PTR(r).str->hashcode;
|
||||
} else {
|
||||
// This is Daniel Bernstein's djb2 hash function that I found
|
||||
// on the web somewhere. It appears to work pretty well.
|
||||
unsigned int i, hash = 5831;
|
||||
for(i=0; i<r.ref.ptr.str->len; i++)
|
||||
hash = (hash * 33) ^ r.ref.ptr.str->data[i];
|
||||
r.ref.ptr.str->hashcode = hash;
|
||||
for(i=0; i<PTR(r).str->len; i++)
|
||||
hash = (hash * 33) ^ PTR(r).str->data[i];
|
||||
PTR(r).str->hashcode = hash;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -49,7 +47,7 @@ static unsigned int hashcolumn(struct HashRec* h, naRef key)
|
||||
return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced);
|
||||
}
|
||||
|
||||
static struct HashRec* hashrealloc(struct naHash* hash)
|
||||
static struct HashRec* resize(struct naHash* hash)
|
||||
{
|
||||
struct HashRec *h, *h0 = hash->rec;
|
||||
int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE;
|
||||
@@ -90,7 +88,7 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
|
||||
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
|
||||
struct HashNode* hn = h->table[col];
|
||||
while(hn) {
|
||||
if(hn->key.ref.ptr.str == sym) {
|
||||
if(PTR(hn->key).str == sym) {
|
||||
*out = hn->val;
|
||||
return 1;
|
||||
}
|
||||
@@ -103,25 +101,32 @@ int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
|
||||
static struct HashNode* find(struct naHash* hash, naRef key)
|
||||
{
|
||||
struct HashRec* h = hash->rec;
|
||||
if(h) {
|
||||
struct HashNode* hn = h->table[hashcolumn(h, key)];
|
||||
while(hn) {
|
||||
if(EQUAL(key, hn->key))
|
||||
return hn;
|
||||
hn = hn->next;
|
||||
}
|
||||
}
|
||||
struct HashNode* hn;
|
||||
if(!h) return 0;
|
||||
for(hn = h->table[hashcolumn(h, key)]; hn; hn = hn->next)
|
||||
if(EQUAL(key, hn->key))
|
||||
return hn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make a temporary string on the stack
|
||||
static void tmpStr(naRef* out, struct naStr* str, char* key)
|
||||
static void tmpStr(naRef* out, struct naStr* str, const char* key)
|
||||
{
|
||||
str->len = 0;
|
||||
str->type = T_STR;
|
||||
str->data = (unsigned char*)key;
|
||||
str->hashcode = 0;
|
||||
while(key[str->len]) str->len++;
|
||||
*out = naNil();
|
||||
out->ref.ptr.str = str;
|
||||
SETPTR(*out, str);
|
||||
}
|
||||
|
||||
int naMember_cget(naRef obj, const char* field, naRef* out)
|
||||
{
|
||||
naRef key;
|
||||
struct naStr str;
|
||||
tmpStr(&key, &str, field);
|
||||
return naMember_get(obj, key, out);
|
||||
}
|
||||
|
||||
naRef naHash_cget(naRef hash, char* key)
|
||||
@@ -145,7 +150,7 @@ void naHash_cset(naRef hash, char* key, naRef val)
|
||||
int naHash_get(naRef hash, naRef key, naRef* out)
|
||||
{
|
||||
if(IS_HASH(hash)) {
|
||||
struct HashNode* n = find(hash.ref.ptr.hash, key);
|
||||
struct HashNode* n = find(PTR(hash).hash, key);
|
||||
if(n) { *out = n->val; return 1; }
|
||||
}
|
||||
return 0;
|
||||
@@ -155,7 +160,7 @@ int naHash_get(naRef hash, naRef key, naRef* out)
|
||||
int naHash_tryset(naRef hash, naRef key, naRef val)
|
||||
{
|
||||
if(IS_HASH(hash)) {
|
||||
struct HashNode* n = find(hash.ref.ptr.hash, key);
|
||||
struct HashNode* n = find(PTR(hash).hash, key);
|
||||
if(n) n->val = val;
|
||||
return n != 0;
|
||||
}
|
||||
@@ -171,8 +176,8 @@ void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
|
||||
int col;
|
||||
struct HashRec* h = hash->rec;
|
||||
while(!h || h->size >= 1<<h->lgalloced)
|
||||
h = hashrealloc(hash);
|
||||
col = (HASH_MAGIC * sym->ref.ptr.str->hashcode) >> (32 - h->lgalloced);
|
||||
h = resize(hash);
|
||||
col = (HASH_MAGIC * PTR(*sym).str->hashcode) >> (32 - h->lgalloced);
|
||||
INSERT(h, *sym, *val, col);
|
||||
}
|
||||
|
||||
@@ -195,10 +200,10 @@ void naHash_set(naRef hash, naRef key, naRef val)
|
||||
struct HashRec* h;
|
||||
struct HashNode* n;
|
||||
if(!IS_HASH(hash)) return;
|
||||
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; }
|
||||
h = hash.ref.ptr.hash->rec;
|
||||
if((n = find(PTR(hash).hash, key))) { n->val = val; return; }
|
||||
h = PTR(hash).hash->rec;
|
||||
while(!h || h->size >= 1<<h->lgalloced)
|
||||
h = hashrealloc(hash.ref.ptr.hash);
|
||||
h = resize(PTR(hash).hash);
|
||||
col = hashcolumn(h, key);
|
||||
INSERT(h, key, val, hashcolumn(h, key));
|
||||
chkcycle(h->table[col], h->size - h->dels);
|
||||
@@ -206,7 +211,7 @@ void naHash_set(naRef hash, naRef key, naRef val)
|
||||
|
||||
void naHash_delete(naRef hash, naRef key)
|
||||
{
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
struct HashRec* h = PTR(hash).hash->rec;
|
||||
int col;
|
||||
struct HashNode *last=0, *hn;
|
||||
if(!IS_HASH(hash) || !h) return;
|
||||
@@ -227,7 +232,7 @@ void naHash_delete(naRef hash, naRef key)
|
||||
void naHash_keys(naRef dst, naRef hash)
|
||||
{
|
||||
int i;
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
struct HashRec* h = PTR(hash).hash->rec;
|
||||
if(!IS_HASH(hash) || !h) return;
|
||||
for(i=0; i<(1<<h->lgalloced); i++) {
|
||||
struct HashNode* hn = h->table[i];
|
||||
@@ -240,7 +245,7 @@ void naHash_keys(naRef dst, naRef hash)
|
||||
|
||||
int naHash_size(naRef hash)
|
||||
{
|
||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
||||
struct HashRec* h = PTR(hash).hash->rec;
|
||||
if(!IS_HASH(hash) || !h) return 0;
|
||||
return h->size - h->dels;
|
||||
}
|
||||
|
||||
+22
-29
@@ -11,7 +11,7 @@ naGhostType naIOGhostType = { ghostDestroy };
|
||||
|
||||
static struct naIOGhost* ioghost(naRef r)
|
||||
{
|
||||
if(naGhost_type(r) == &naIOGhostType)
|
||||
if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
|
||||
return naGhost_ptr(r);
|
||||
return 0;
|
||||
}
|
||||
@@ -32,9 +32,9 @@ static naRef f_read(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef len = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if(!g || !MUTABLE(str) || !IS_NUM(len))
|
||||
naRuntimeError(c, "bad argument to read()");
|
||||
if(str.ref.ptr.str->len < (int)len.num)
|
||||
if(PTR(str).str->len < (int)len.num)
|
||||
naRuntimeError(c, "string not big enough for read");
|
||||
return naNum(g->type->read(c, g->handle, (char*)str.ref.ptr.str->data,
|
||||
return naNum(g->type->read(c, g->handle, (char*)PTR(str).str->data,
|
||||
(int)len.num));
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ static naRef f_write(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef str = argc > 1 ? args[1] : naNil();
|
||||
if(!g || !IS_STR(str))
|
||||
naRuntimeError(c, "bad argument to write()");
|
||||
return naNum(g->type->write(c, g->handle, (char*)str.ref.ptr.str->data,
|
||||
str.ref.ptr.str->len));
|
||||
return naNum(g->type->write(c, g->handle, (char*)PTR(str).str->data,
|
||||
PTR(str).str->len));
|
||||
}
|
||||
|
||||
static naRef f_seek(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -113,7 +113,8 @@ static int iotell(naContext c, void* f)
|
||||
|
||||
static void iodestroy(void* f)
|
||||
{
|
||||
ioclose(0, f);
|
||||
if(f != stdin && f != stdout && f != stderr)
|
||||
ioclose(0, f);
|
||||
}
|
||||
|
||||
struct naIOType naStdIOType = { ioclose, ioread, iowrite, ioseek,
|
||||
@@ -133,8 +134,8 @@ static naRef f_open(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil();
|
||||
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
|
||||
if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
|
||||
f = fopen((char*)file.ref.ptr.str->data,
|
||||
IS_STR(mode) ? (const char*)mode.ref.ptr.str->data : "r");
|
||||
f = fopen((char*)PTR(file).str->data,
|
||||
IS_STR(mode) ? (const char*)PTR(mode).str->data : "rb");
|
||||
if(!f) naRuntimeError(c, strerror(errno));
|
||||
return naIOGhost(c, f);
|
||||
}
|
||||
@@ -169,7 +170,8 @@ static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
|
||||
if(c == '\r') {
|
||||
char c2 = getcguard(ctx, g->handle, buf);
|
||||
if(c2 != EOF && c2 != '\n')
|
||||
ungetc(c2, g->handle);
|
||||
if(EOF == ungetc(c2, g->handle))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
buf[i++] = c;
|
||||
@@ -186,7 +188,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
|
||||
struct stat s;
|
||||
naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
|
||||
if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()");
|
||||
if(stat((char*)path.ref.ptr.str->data, &s) < 0) {
|
||||
if(stat((char*)PTR(path).str->data, &s) < 0) {
|
||||
if(errno == ENOENT) return naNil();
|
||||
naRuntimeError(ctx, strerror(errno));
|
||||
}
|
||||
@@ -199,7 +201,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "close", f_close },
|
||||
{ "read", f_read },
|
||||
{ "write", f_write },
|
||||
@@ -208,26 +210,17 @@ static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
{ "open", f_open },
|
||||
{ "readln", f_readln },
|
||||
{ "stat", f_stat },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void setsym(naContext c, naRef hash, char* sym, naRef val)
|
||||
naRef naInit_io(naContext c)
|
||||
{
|
||||
naRef name = naStr_fromdata(naNewString(c), sym, strlen(sym));
|
||||
naHash_set(hash, naInternSymbol(name), val);
|
||||
}
|
||||
|
||||
naRef naIOLib(naContext c)
|
||||
{
|
||||
naRef ns = naNewHash(c);
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++)
|
||||
setsym(c, ns, funcs[i].name,
|
||||
naNewFunc(c, naNewCCode(c, funcs[i].func)));
|
||||
setsym(c, ns, "SEEK_SET", naNum(SEEK_SET));
|
||||
setsym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
|
||||
setsym(c, ns, "SEEK_END", naNum(SEEK_END));
|
||||
setsym(c, ns, "stdin", naIOGhost(c, stdin));
|
||||
setsym(c, ns, "stdout", naIOGhost(c, stdout));
|
||||
setsym(c, ns, "stderr", naIOGhost(c, stderr));
|
||||
naRef ns = naGenLib(c, funcs);
|
||||
naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
|
||||
naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
|
||||
naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
|
||||
naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
|
||||
naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
|
||||
naAddSym(c, ns, "stderr", naIOGhost(c, stderr));
|
||||
return ns;
|
||||
}
|
||||
|
||||
+29
-11
@@ -109,7 +109,20 @@ static int lineEnd(struct Parser* p, int line)
|
||||
static void newToken(struct Parser* p, int pos, int type,
|
||||
char* str, int slen, double num)
|
||||
{
|
||||
struct Token* tok;
|
||||
struct Token *tok, *last = p->tree.lastChild;
|
||||
|
||||
/* Adjacent string literals get concatenated */
|
||||
if(type == TOK_LITERAL && str) {
|
||||
if(last && last->type == TOK_LITERAL) {
|
||||
int i, len1 = last->strlen;
|
||||
char* str2 = naParseAlloc(p, len1 + slen);
|
||||
for(i=0; i<len1; i++) str2[i] = last->str[i];
|
||||
for(i=0; i<slen; i++) str2[i+len1] = str[i];
|
||||
last->str = str2;
|
||||
last->strlen += slen;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tok = naParseAlloc(p, sizeof(struct Token));
|
||||
tok->type = type;
|
||||
@@ -119,17 +132,18 @@ static void newToken(struct Parser* p, int pos, int type,
|
||||
tok->num = num;
|
||||
tok->parent = &p->tree;
|
||||
tok->next = 0;
|
||||
tok->prev = p->tree.lastChild;
|
||||
tok->prev = last;
|
||||
tok->children = 0;
|
||||
tok->lastChild = 0;
|
||||
|
||||
// Context sensitivity hack: a "-" following a binary operator of
|
||||
// higher precedence (MUL and DIV, basically) must be a unary
|
||||
// negation. Needed to get precedence right in the parser for
|
||||
// expressiong like "a * -2"
|
||||
if(type == TOK_MINUS && tok->prev)
|
||||
if(tok->prev->type == TOK_MUL || tok->prev->type == TOK_DIV)
|
||||
// equal or higher precedence must be a unary negation. Needed to
|
||||
// get precedence right in the parser for expressiong like "a * -2"
|
||||
if(type == TOK_MINUS && tok->prev) {
|
||||
int pt = tok->prev->type;
|
||||
if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV)
|
||||
tok->type = type = TOK_NEG;
|
||||
}
|
||||
|
||||
if(!p->tree.children) p->tree.children = tok;
|
||||
if(p->tree.lastChild) p->tree.lastChild->next = tok;
|
||||
@@ -179,6 +193,7 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p,
|
||||
case 'n': *cOut = '\n'; break;
|
||||
case 't': *cOut = '\t'; break;
|
||||
case '\\': *cOut = '\\'; break;
|
||||
case '`': *cOut = '`'; break;
|
||||
case 'x':
|
||||
if(len < 4) error(p, "unterminated string", index);
|
||||
*cOut = (char)((hexc(buf[2], p, index)<<4) | hexc(buf[3], p, index));
|
||||
@@ -191,11 +206,12 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: should handle UTF8 too
|
||||
static void charLiteral(struct Parser* p, int index, char* s, int len)
|
||||
{
|
||||
if(len != 1) error(p, "character constant not single character", index);
|
||||
newToken(p, index, TOK_LITERAL, 0, 0, *s);
|
||||
int n, c;
|
||||
c = naLexUtf8C(s, len, &n);
|
||||
if(c < 0 || n != len) error(p, "invalid utf8 character constant", index);
|
||||
newToken(p, index, TOK_LITERAL, 0, 0, c);
|
||||
}
|
||||
|
||||
// Read in a string literal
|
||||
@@ -317,6 +333,7 @@ static int tryLexemes(struct Parser* p, int index, int* lexemeOut)
|
||||
return best;
|
||||
}
|
||||
|
||||
#define ISNUM(c) ((c) >= '0' && (c) <= '9')
|
||||
void naLex(struct Parser* p)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -338,7 +355,8 @@ void naLex(struct Parser* p)
|
||||
i = lexStringLiteral(p, i, c);
|
||||
break;
|
||||
default:
|
||||
if(c >= '0' && c <= '9') i = lexNumLiteral(p, i);
|
||||
if(ISNUM(c) || (c == '.' && (i+1)<p->len && ISNUM(p->buf[i+1])))
|
||||
i = lexNumLiteral(p, i);
|
||||
else handled = 0;
|
||||
}
|
||||
|
||||
|
||||
+232
-145
@@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER // sigh...
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
@@ -14,9 +15,14 @@
|
||||
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
|
||||
#define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
|
||||
|
||||
static naRef size(naContext c, naRef me, int argc, naRef* args)
|
||||
// Generic argument error, assumes that the symbol "c" is a naContext,
|
||||
// and that the __FUNCTION__ string is of the form "f_NASALSYMBOL".
|
||||
#define ARGERR() \
|
||||
naRuntimeError(c, "bad/missing argument to %s()", (__FUNCTION__ + 2))
|
||||
|
||||
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc == 0) return naNil();
|
||||
if(argc == 0) ARGERR();
|
||||
if(naIsString(args[0])) return naNum(naStr_len(args[0]));
|
||||
if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
|
||||
if(naIsHash(args[0])) return naNum(naHash_size(args[0]));
|
||||
@@ -24,41 +30,37 @@ static naRef size(naContext c, naRef me, int argc, naRef* args)
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef keys(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_keys(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef v, h = args[0];
|
||||
if(!naIsHash(h)) return naNil();
|
||||
naRef v, h = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsHash(h)) ARGERR();
|
||||
v = naNewVector(c);
|
||||
naHash_keys(v, h);
|
||||
return v;
|
||||
}
|
||||
|
||||
static naRef append(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_append(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
if(argc < 2) return naNil();
|
||||
if(!naIsVector(args[0])) return naNil();
|
||||
if(argc < 2 || !naIsVector(args[0])) ARGERR();
|
||||
for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef pop(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_pop(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc < 1 || !naIsVector(args[0])) return naNil();
|
||||
if(argc < 1 || !naIsVector(args[0])) ARGERR();
|
||||
return naVec_removelast(args[0]);
|
||||
}
|
||||
|
||||
static naRef setsize(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_setsize(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int sz;
|
||||
if(argc < 2) return naNil();
|
||||
sz = (int)naNumValue(args[1]).num;
|
||||
if(!naIsVector(args[0])) return naNil();
|
||||
naVec_setsize(args[0], sz);
|
||||
if(argc < 2 || !naIsVector(args[0])) ARGERR();
|
||||
naVec_setsize(args[0], (int)naNumValue(args[1]).num);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef nlen, result, v = args[0];
|
||||
@@ -67,8 +69,8 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
nlen = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if(!naIsNil(nlen))
|
||||
len = (int)nlen.num;
|
||||
if(!naIsVector(v) || start < 0 || start >= naVec_size(v) || len < 0)
|
||||
return naNil();
|
||||
if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
|
||||
ARGERR();
|
||||
if(naIsNil(nlen) || len > naVec_size(v) - start)
|
||||
len = naVec_size(v) - start;
|
||||
result = naNewVector(c);
|
||||
@@ -78,13 +80,14 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef delete(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_delete(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 1 && naIsHash(args[0])) naHash_delete(args[0], args[1]);
|
||||
return naNil();
|
||||
if(argc < 2 || !naIsHash(args[0])) ARGERR();
|
||||
naHash_delete(args[0], args[1]);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static naRef intf(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_int(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0) {
|
||||
naRef n = naNumValue(args[0]);
|
||||
@@ -92,15 +95,16 @@ static naRef intf(naContext c, naRef me, int argc, naRef* args)
|
||||
if(n.num < 0) n.num = -floor(-n.num);
|
||||
else n.num = floor(n.num);
|
||||
return n;
|
||||
} else return naNil();
|
||||
} else ARGERR();
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef num(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_num(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return argc > 0 ? naNumValue(args[0]) : naNil();
|
||||
}
|
||||
|
||||
static naRef streq(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_streq(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil();
|
||||
}
|
||||
@@ -110,7 +114,7 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
|
||||
char *a, *b;
|
||||
int i, alen, blen;
|
||||
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
|
||||
naRuntimeError(c, "bad argument to cmp");
|
||||
ARGERR();
|
||||
a = naStr_data(args[0]);
|
||||
alen = naStr_len(args[0]);
|
||||
b = naStr_data(args[1]);
|
||||
@@ -122,45 +126,45 @@ static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
|
||||
return naNum(alen == blen ? 0 : (alen < blen ? -1 : 1));
|
||||
}
|
||||
|
||||
static naRef substr(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef src = argc > 1 ? args[0] : naNil();
|
||||
naRef startR = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||
naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
int start, len;
|
||||
if(!naIsString(src)) return naNil();
|
||||
if(naIsNil(startR)) return naNil();
|
||||
start = (int)startR.num;
|
||||
if(naIsNil(lenR)) {
|
||||
len = naStr_len(src) - start;
|
||||
if(len < 0) return naNil();
|
||||
} else {
|
||||
lenR = naNumValue(lenR);
|
||||
if(naIsNil(lenR)) return naNil();
|
||||
len = (int)lenR.num;
|
||||
}
|
||||
int start, len, srclen;
|
||||
naRef src = argc > 0 ? args[0] : naNil();
|
||||
naRef startr = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||
naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if(!naIsString(src)) ARGERR();
|
||||
if(naIsNil(startr) || !naIsNum(startr)) ARGERR();
|
||||
if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR();
|
||||
srclen = naStr_len(src);
|
||||
start = (int)startr.num;
|
||||
len = naIsNum(lenr) ? (int)lenr.num : (srclen - start);
|
||||
if(start < 0) start += srclen;
|
||||
if(start < 0) start = len = 0;
|
||||
if(start >= srclen) start = len = 0;
|
||||
if(len < 0) len = 0;
|
||||
if(len > srclen - start) len = srclen - start;
|
||||
return naStr_substr(naNewString(c), src, start, len);
|
||||
}
|
||||
|
||||
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
char chr[1];
|
||||
naRef cr = argc ? naNumValue(args[0]) : naNil();
|
||||
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string");
|
||||
naRef cr = argc > 0 ? naNumValue(args[0]) : naNil();
|
||||
if(IS_NIL(cr)) ARGERR();
|
||||
chr[0] = (char)cr.num;
|
||||
return NEWSTR(c, chr, 1);
|
||||
}
|
||||
|
||||
static naRef contains(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_contains(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef hash = argc > 0 ? args[0] : naNil();
|
||||
naRef key = argc > 1 ? args[1] : naNil();
|
||||
if(naIsNil(hash) || naIsNil(key)) return naNil();
|
||||
if(naIsNil(hash) || naIsNil(key)) ARGERR();
|
||||
if(!naIsHash(hash)) return naNil();
|
||||
return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
|
||||
}
|
||||
|
||||
static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
|
||||
static naRef f_typeof(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef r = argc > 0 ? args[0] : naNil();
|
||||
char* t = "unknown";
|
||||
@@ -171,8 +175,20 @@ static naRef typeOf(naContext c, naRef me, int argc, naRef* args)
|
||||
else if(naIsHash(r)) t = "hash";
|
||||
else if(naIsFunc(r)) t = "func";
|
||||
else if(naIsGhost(r)) t = "ghost";
|
||||
r = NEWCSTR(c, t);
|
||||
return r;
|
||||
return NEWCSTR(c, t);
|
||||
}
|
||||
|
||||
static naRef f_ghosttype(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef g = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsGhost(g)) return naNil();
|
||||
if(naGhost_type(g)->name) {
|
||||
return NEWCSTR(c, (char*)naGhost_type(g)->name);
|
||||
} else {
|
||||
char buf[32];
|
||||
sprintf(buf, "%p", naGhost_type(g));
|
||||
return NEWCSTR(c, buf);
|
||||
}
|
||||
}
|
||||
|
||||
static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -180,14 +196,24 @@ static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
|
||||
int errLine;
|
||||
naRef script, code, fname;
|
||||
script = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsString(script)) return naNil();
|
||||
fname = NEWCSTR(c, "<compile>");
|
||||
fname = argc > 1 ? args[1] : NEWCSTR(c, "<compile>");
|
||||
if(!naIsString(script) || !naIsString(fname)) return naNil();
|
||||
code = naParseCode(c, fname, 1,
|
||||
naStr_data(script), naStr_len(script), &errLine);
|
||||
if(!naIsCode(code)) return naNil(); // FIXME: export error to caller...
|
||||
if(naIsNil(code)) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Parse error: %s at line %d",
|
||||
naGetError(c), errLine);
|
||||
c->dieArg = NEWCSTR(c, buf);
|
||||
naRuntimeError(c, "__die__");
|
||||
}
|
||||
return naBindToContext(c, code);
|
||||
}
|
||||
|
||||
// FIXME: need a place to save the current IP when we get an error so
|
||||
// that it can be reset if we get a die()/naRethrowError() situation
|
||||
// later. Right now, the IP on the stack trace is the line of the
|
||||
// die() call, when it should be this one...
|
||||
static naRef f_call(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naContext subc;
|
||||
@@ -199,33 +225,49 @@ static naRef f_call(naContext c, naRef me, int argc, naRef* args)
|
||||
if(!IS_HASH(callme)) callme = naNil();
|
||||
if(!IS_HASH(callns)) callns = naNil();
|
||||
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
|
||||
naRuntimeError(c, "bad argument to call()");
|
||||
subc = naNewContext();
|
||||
subc->callParent = c;
|
||||
c->callChild = subc;
|
||||
vr = IS_NIL(callargs) ? 0 : callargs.ref.ptr.vec->rec;
|
||||
ARGERR();
|
||||
|
||||
subc = naSubContext(c);
|
||||
vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
|
||||
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
|
||||
callme, callns);
|
||||
c->callChild = 0;
|
||||
if(argc > 2 && IS_VEC(args[argc-1])) {
|
||||
if(!IS_NIL(subc->dieArg)) naVec_append(args[argc-1], subc->dieArg);
|
||||
else if(naGetError(subc))
|
||||
naVec_append(args[argc-1], NEWCSTR(subc, naGetError(subc)));
|
||||
if(!naGetError(subc)) {
|
||||
naFreeContext(subc);
|
||||
return result;
|
||||
}
|
||||
naFreeContext(subc);
|
||||
return result;
|
||||
|
||||
// Error handling. Note that we don't free the subcontext after an
|
||||
// error, in case the user re-throws the same error or calls
|
||||
// naContinue()
|
||||
if(argc <= 2 || !IS_VEC(args[argc-1])) {
|
||||
naRethrowError(subc);
|
||||
} else {
|
||||
int i, sd;
|
||||
naRef errv = args[argc-1];
|
||||
if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg);
|
||||
else naVec_append(errv, NEWCSTR(subc, naGetError(subc)));
|
||||
sd = naStackDepth(subc);
|
||||
for(i=0; i<sd; i++) {
|
||||
naVec_append(errv, naGetSourceFile(subc, i));
|
||||
naVec_append(errv, naNum(naGetLine(subc, i)));
|
||||
}
|
||||
}
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_die(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
c->dieArg = argc > 0 ? args[0] : naNil();
|
||||
naRef darg = argc > 0 ? args[0] : naNil();
|
||||
if(!naIsNil(darg) && c->callChild && IDENTICAL(c->callChild->dieArg, darg))
|
||||
naRethrowError(c->callChild);
|
||||
c->dieArg = darg;
|
||||
naRuntimeError(c, "__die__");
|
||||
return naNil(); // never executes
|
||||
}
|
||||
|
||||
// Wrapper around vsnprintf, iteratively increasing the buffer size
|
||||
// until it fits. Returned buffer should be freed by the caller.
|
||||
char* dosprintf(char* f, ...)
|
||||
static char* dosprintf(char* f, ...)
|
||||
{
|
||||
char* buf;
|
||||
va_list va;
|
||||
@@ -251,7 +293,7 @@ char* dosprintf(char* f, ...)
|
||||
// all of ANSI C's syntax except for the "length modifier" feature.
|
||||
// Note: this does not validate the format character returned in
|
||||
// "type". That is the caller's job.
|
||||
static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type)
|
||||
static char* nextFormat(naContext c, char* f, char** out, int* len, char* type)
|
||||
{
|
||||
// Skip to the start of the format string
|
||||
while(*f && *f != '%') f++;
|
||||
@@ -266,44 +308,44 @@ static char* nextFormat(naContext ctx, char* f, char** out, int* len, char* type
|
||||
for(p1 = *out + 1; p1 < f; p1++)
|
||||
for(p2 = p1+1; p2 < f; p2++)
|
||||
if(*p1 == *p2)
|
||||
naRuntimeError(ctx, "duplicate flag in format string"); }
|
||||
naRuntimeError(c, "duplicate flag in format string"); }
|
||||
|
||||
while(*f && *f >= '0' && *f <= '9') f++;
|
||||
if(*f && *f == '.') f++;
|
||||
while(*f && *f >= '0' && *f <= '9') f++;
|
||||
if(!*f) naRuntimeError(ctx, "invalid format string");
|
||||
if(!*f) naRuntimeError(c, "invalid format string");
|
||||
|
||||
*type = *f++;
|
||||
*len = f - *out;
|
||||
return f;
|
||||
}
|
||||
|
||||
#define ERR(m) naRuntimeError(ctx, m)
|
||||
#define APPEND(r) result = naStr_concat(naNewString(ctx), result, r)
|
||||
static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
|
||||
#define ERR(m) naRuntimeError(c, m)
|
||||
#define APPEND(r) result = naStr_concat(naNewString(c), result, r)
|
||||
static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
char t, nultmp, *fstr, *next, *fout=0, *s;
|
||||
int flen, argn=1;
|
||||
naRef format, arg, result = naNewString(ctx);
|
||||
naRef format, arg, result = naNewString(c);
|
||||
|
||||
if(argc < 1) ERR("not enough arguments to sprintf");
|
||||
format = naStringValue(ctx, argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(format)) ERR("bad format string in sprintf");
|
||||
if(argc < 1) ERR("not enough arguments to sprintf()");
|
||||
format = naStringValue(c, argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(format)) ERR("bad format string in sprintf()");
|
||||
s = naStr_data(format);
|
||||
|
||||
while((next = nextFormat(ctx, s, &fstr, &flen, &t))) {
|
||||
APPEND(NEWSTR(ctx, s, fstr-s)); // stuff before the format string
|
||||
while((next = nextFormat(c, s, &fstr, &flen, &t))) {
|
||||
APPEND(NEWSTR(c, s, fstr-s)); // stuff before the format string
|
||||
if(flen == 2 && fstr[1] == '%') {
|
||||
APPEND(NEWSTR(ctx, "%", 1));
|
||||
APPEND(NEWSTR(c, "%", 1));
|
||||
s = next;
|
||||
continue;
|
||||
}
|
||||
if(argn >= argc) ERR("not enough arguments to sprintf");
|
||||
if(argn >= argc) ERR("not enough arguments to sprintf()");
|
||||
arg = args[argn++];
|
||||
nultmp = fstr[flen]; // sneaky nul termination...
|
||||
fstr[flen] = 0;
|
||||
if(t == 's') {
|
||||
arg = naStringValue(ctx, arg);
|
||||
arg = naStringValue(c, arg);
|
||||
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
|
||||
else fout = dosprintf(fstr, naStr_data(arg));
|
||||
} else {
|
||||
@@ -320,44 +362,42 @@ static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
|
||||
ERR("invalid sprintf format type");
|
||||
}
|
||||
fstr[flen] = nultmp;
|
||||
APPEND(NEWSTR(ctx, fout, strlen(fout)));
|
||||
APPEND(NEWSTR(c, fout, strlen(fout)));
|
||||
naFree(fout);
|
||||
s = next;
|
||||
}
|
||||
APPEND(NEWSTR(ctx, s, strlen(s)));
|
||||
APPEND(NEWSTR(c, s, strlen(s)));
|
||||
return result;
|
||||
}
|
||||
|
||||
// FIXME: handle ctx->callParent frames too!
|
||||
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args)
|
||||
// FIXME: needs to honor subcontext list
|
||||
static naRef f_caller(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int fidx;
|
||||
struct Frame* frame;
|
||||
naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
|
||||
if(IS_NIL(fr)) naRuntimeError(ctx, "non numeric argument to caller()");
|
||||
if(IS_NIL(fr)) ARGERR();
|
||||
fidx = (int)fr.num;
|
||||
if(fidx > ctx->fTop - 1) return naNil();
|
||||
frame = &ctx->fStack[ctx->fTop - 1 - fidx];
|
||||
result = naNewVector(ctx);
|
||||
if(fidx > c->fTop - 1) return naNil();
|
||||
frame = &c->fStack[c->fTop - 1 - fidx];
|
||||
result = naNewVector(c);
|
||||
naVec_append(result, frame->locals);
|
||||
naVec_append(result, frame->func);
|
||||
naVec_append(result, frame->func.ref.ptr.func->code.ref.ptr.code->srcFile);
|
||||
naVec_append(result, naNum(naGetLine(ctx, fidx)));
|
||||
naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
|
||||
naVec_append(result, naNum(naGetLine(c, fidx)));
|
||||
return result;
|
||||
}
|
||||
|
||||
static naRef f_closure(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_closure(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
naRef func, idx;
|
||||
struct naFunc* f;
|
||||
func = argc > 0 ? args[0] : naNil();
|
||||
idx = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||
if(!IS_FUNC(func) || IS_NIL(idx))
|
||||
naRuntimeError(ctx, "bad arguments to closure()");
|
||||
naRef func = argc > 0 ? args[0] : naNil();
|
||||
naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
|
||||
if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
|
||||
i = (int)idx.num;
|
||||
f = func.ref.ptr.func;
|
||||
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; }
|
||||
f = PTR(func).func;
|
||||
while(i > 0 && f) { i--; f = PTR(f->next).func; }
|
||||
if(!f) return naNil();
|
||||
return f->namespace;
|
||||
}
|
||||
@@ -377,40 +417,38 @@ static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static naRef f_find(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_find(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int start = 0;
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
|
||||
naRuntimeError(ctx, "bad/missing argument to find");
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
|
||||
if(argc > 2) start = (int)(naNumValue(args[2]).num);
|
||||
return naNum(find(args[0].ref.ptr.str->data, args[0].ref.ptr.str->len,
|
||||
args[1].ref.ptr.str->data, args[1].ref.ptr.str->len,
|
||||
return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len,
|
||||
PTR(args[1]).str->data, PTR(args[1]).str->len,
|
||||
start));
|
||||
}
|
||||
|
||||
static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_split(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int sl, dl, i;
|
||||
char *s, *d, *s0;
|
||||
naRef result;
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
|
||||
naRuntimeError(ctx, "bad/missing argument to split");
|
||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
|
||||
d = naStr_data(args[0]); dl = naStr_len(args[0]);
|
||||
s = naStr_data(args[1]); sl = naStr_len(args[1]);
|
||||
result = naNewVector(ctx);
|
||||
result = naNewVector(c);
|
||||
if(dl == 0) { // special case zero-length delimiter
|
||||
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(ctx, s+i, 1));
|
||||
for(i=0; i<sl; i++) naVec_append(result, NEWSTR(c, s+i, 1));
|
||||
return result;
|
||||
}
|
||||
s0 = s;
|
||||
for(i=0; i <= sl-dl; i++) {
|
||||
if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
|
||||
naVec_append(result, NEWSTR(ctx, s0, s+i-s0));
|
||||
naVec_append(result, NEWSTR(c, s0, s+i-s0));
|
||||
s0 = s + i + dl;
|
||||
i += dl - 1;
|
||||
}
|
||||
}
|
||||
if(s0 - s <= sl) naVec_append(result, NEWSTR(ctx, s0, s+sl-s0));
|
||||
if(s0 - s <= sl) naVec_append(result, NEWSTR(c, s0, s+sl-s0));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -418,12 +456,12 @@ static naRef f_split(naContext ctx, naRef me, int argc, naRef* args)
|
||||
// function, which is usually not threadsafe and often of limited
|
||||
// precision. The 5x loop guarantees that we get a full double worth
|
||||
// of precision even for 15 bit (Win32...) rand() implementations.
|
||||
static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
double r = 0;
|
||||
if(argc) {
|
||||
if(!IS_NUM(args[0])) naRuntimeError(ctx, "rand() seed not number");
|
||||
if(!IS_NUM(args[0])) naRuntimeError(c, "rand() seed not number");
|
||||
srand((unsigned int)args[0].num);
|
||||
return naNil();
|
||||
}
|
||||
@@ -431,36 +469,91 @@ static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
|
||||
return naNum(r);
|
||||
}
|
||||
|
||||
static naRef f_bind(naContext ctx, naRef me, int argc, naRef* args)
|
||||
static naRef f_bind(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef func = argc > 0 ? args[0] : naNil();
|
||||
naRef hash = argc > 1 ? args[1] : naNewHash(ctx);
|
||||
naRef hash = argc > 1 ? args[1] : naNewHash(c);
|
||||
naRef next = argc > 2 ? args[2] : naNil();
|
||||
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
|
||||
naRuntimeError(ctx, "bad argument to bind");
|
||||
func = naNewFunc(ctx, func.ref.ptr.func->code);
|
||||
func.ref.ptr.func->namespace = hash;
|
||||
func.ref.ptr.func->next = next;
|
||||
ARGERR();
|
||||
func = naNewFunc(c, PTR(func).func->code);
|
||||
PTR(func).func->namespace = hash;
|
||||
PTR(func).func->next = next;
|
||||
return func;
|
||||
}
|
||||
|
||||
struct func { char* name; naCFunction func; };
|
||||
static struct func funcs[] = {
|
||||
{ "size", size },
|
||||
{ "keys", keys },
|
||||
{ "append", append },
|
||||
{ "pop", pop },
|
||||
{ "setsize", setsize },
|
||||
{ "subvec", subvec },
|
||||
{ "delete", delete },
|
||||
{ "int", intf },
|
||||
{ "num", num },
|
||||
{ "streq", streq },
|
||||
/* We use the "SortRec" gadget for two reasons: first, because ANSI
|
||||
* qsort() doesn't give us a mechanism for passing a "context" pointer
|
||||
* to the comparison routine we have to store one in every sorted
|
||||
* record. Second, using an index into the original vector here
|
||||
* allows us to make the sort stable in the event of a zero returned
|
||||
* from the Nasal comparison function. */
|
||||
struct SortData { naContext ctx, subc; struct SortRec* recs;
|
||||
naRef* elems; int n; naRef fn; };
|
||||
struct SortRec { struct SortData* sd; int i; };
|
||||
|
||||
static int sortcmp(struct SortRec* a, struct SortRec* b)
|
||||
{
|
||||
struct SortData* sd = a->sd;
|
||||
naRef args[2], d;
|
||||
args[0] = sd->elems[a->i];
|
||||
args[1] = sd->elems[b->i];
|
||||
d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil());
|
||||
if(naGetError(sd->subc)) {
|
||||
naFree(sd->recs);
|
||||
naRethrowError(sd->subc);
|
||||
} else if(!naIsNum(d = naNumValue(d))) {
|
||||
naFree(sd->recs);
|
||||
naRuntimeError(sd->ctx, "sort() comparison returned non-number");
|
||||
}
|
||||
return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i));
|
||||
}
|
||||
|
||||
static naRef f_sort(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int i;
|
||||
struct SortData sd;
|
||||
naRef out;
|
||||
if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1]))
|
||||
naRuntimeError(c, "bad/missing argument to sort()");
|
||||
sd.subc = naSubContext(c);
|
||||
if(!PTR(args[0]).vec->rec) return naNewVector(c);
|
||||
sd.elems = PTR(args[0]).vec->rec->array;
|
||||
sd.n = PTR(args[0]).vec->rec->size;
|
||||
sd.fn = args[1];
|
||||
sd.recs = naAlloc(sizeof(struct SortRec) * sd.n);
|
||||
for(i=0; i<sd.n; i++) {
|
||||
sd.recs[i].sd = &sd;
|
||||
sd.recs[i].i = i;
|
||||
}
|
||||
qsort(sd.recs, sd.n, sizeof(sd.recs[0]),
|
||||
(int(*)(const void*,const void*))sortcmp);
|
||||
out = naNewVector(c);
|
||||
naVec_setsize(out, sd.n);
|
||||
for(i=0; i<sd.n; i++)
|
||||
PTR(out).vec->rec->array[i] = sd.elems[sd.recs[i].i];
|
||||
naFree(sd.recs);
|
||||
naFreeContext(sd.subc);
|
||||
return out;
|
||||
}
|
||||
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "size", f_size },
|
||||
{ "keys", f_keys },
|
||||
{ "append", f_append },
|
||||
{ "pop", f_pop },
|
||||
{ "setsize", f_setsize },
|
||||
{ "subvec", f_subvec },
|
||||
{ "delete", f_delete },
|
||||
{ "int", f_int },
|
||||
{ "num", f_num },
|
||||
{ "streq", f_streq },
|
||||
{ "cmp", f_cmp },
|
||||
{ "substr", substr },
|
||||
{ "substr", f_substr },
|
||||
{ "chr", f_chr },
|
||||
{ "contains", contains },
|
||||
{ "typeof", typeOf },
|
||||
{ "contains", f_contains },
|
||||
{ "typeof", f_typeof },
|
||||
{ "ghosttype", f_ghosttype },
|
||||
{ "compile", f_compile },
|
||||
{ "call", f_call },
|
||||
{ "die", f_die },
|
||||
@@ -471,17 +564,11 @@ static struct func funcs[] = {
|
||||
{ "split", f_split },
|
||||
{ "rand", f_rand },
|
||||
{ "bind", f_bind },
|
||||
{ "sort", f_sort },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naStdLib(naContext c)
|
||||
naRef naInit_std(naContext c)
|
||||
{
|
||||
naRef namespace = naNewHash(c);
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++) {
|
||||
naRef code = naNewCCode(c, funcs[i].func);
|
||||
naRef name = NEWSTR(c, funcs[i].name, strlen(funcs[i].name));
|
||||
name = naInternSymbol(name);
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
return namespace;
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
|
||||
+30
-28
@@ -1,16 +1,32 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
// Toss a runtime error for any NaN or Inf values produced. Note that
|
||||
// this assumes an IEEE 754 format.
|
||||
#define VALIDATE(r) (valid(r.num) ? (r) : die(c, __FUNCTION__+2))
|
||||
|
||||
static int valid(double d)
|
||||
{
|
||||
union { double d; unsigned long long ull; } u;
|
||||
u.d = d;
|
||||
return ((u.ull >> 52) & 0x7ff) != 0x7ff;
|
||||
}
|
||||
|
||||
static naRef die(naContext c, const char* fn)
|
||||
{
|
||||
naRuntimeError(c, "floating point error in math.%s()", fn);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to sin()");
|
||||
a.num = sin(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -19,7 +35,7 @@ static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to cos()");
|
||||
a.num = cos(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -28,7 +44,7 @@ static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to exp()");
|
||||
a.num = exp(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -37,7 +53,7 @@ static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to ln()");
|
||||
a.num = log(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -46,7 +62,7 @@ static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric argument to sqrt()");
|
||||
a.num = sqrt(a.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
|
||||
@@ -56,37 +72,23 @@ static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
|
||||
if(naIsNil(a) || naIsNil(b))
|
||||
naRuntimeError(c, "non numeric argument to atan2()");
|
||||
a.num = atan2(a.num, b.num);
|
||||
return a;
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "sin", f_sin },
|
||||
{ "cos", f_cos },
|
||||
{ "exp", f_exp },
|
||||
{ "ln", f_ln },
|
||||
{ "sqrt", f_sqrt },
|
||||
{ "atan2", f_atan2 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naMathLib(naContext c)
|
||||
naRef naInit_math(naContext c)
|
||||
{
|
||||
naRef name, namespace = naNewHash(c);
|
||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
||||
for(i=0; i<n; i++) {
|
||||
naRef code = naNewCCode(c, funcs[i].func);
|
||||
naRef name = naStr_fromdata(naNewString(c),
|
||||
funcs[i].name, strlen(funcs[i].name));
|
||||
naHash_set(namespace, name, naNewFunc(c, code));
|
||||
}
|
||||
|
||||
// Set up constants for math.pi and math.e. Can't use M_PI or
|
||||
// M_E, becuase those aren't technically part of the C standard. Sigh.
|
||||
name = naStr_fromdata(naNewString(c), "pi", 2);
|
||||
naHash_set(namespace, name, naNum(3.14159265358979323846));
|
||||
|
||||
name = naStr_fromdata(naNewString(c), "e", 1);
|
||||
name = naInternSymbol(name);
|
||||
naHash_set(namespace, name, naNum(2.7182818284590452354));
|
||||
|
||||
return namespace;
|
||||
naRef ns = naGenLib(c, funcs);
|
||||
naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
|
||||
naAddSym(c, ns, "e", naNum(2.7182818284590452354));
|
||||
return ns;
|
||||
}
|
||||
|
||||
+43
-25
@@ -23,14 +23,13 @@ void naTempSave(naContext c, naRef r)
|
||||
naFree(c->temps);
|
||||
c->temps = newtemps;
|
||||
}
|
||||
c->temps[c->ntemps++] = r.ref.ptr.obj;
|
||||
c->temps[c->ntemps++] = PTR(r).obj;
|
||||
}
|
||||
|
||||
naRef naObj(int type, struct naObj* o)
|
||||
{
|
||||
naRef r;
|
||||
r.ref.reftag = NASAL_REFTAG;
|
||||
r.ref.ptr.obj = o;
|
||||
SETPTR(r, o);
|
||||
o->type = type;
|
||||
return r;
|
||||
}
|
||||
@@ -78,23 +77,23 @@ naRef naNew(struct Context* c, int type)
|
||||
naRef naNewString(struct Context* c)
|
||||
{
|
||||
naRef s = naNew(c, T_STR);
|
||||
s.ref.ptr.str->len = 0;
|
||||
s.ref.ptr.str->data = 0;
|
||||
s.ref.ptr.str->hashcode = 0;
|
||||
PTR(s).str->len = 0;
|
||||
PTR(s).str->data = 0;
|
||||
PTR(s).str->hashcode = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
naRef naNewVector(struct Context* c)
|
||||
{
|
||||
naRef r = naNew(c, T_VEC);
|
||||
r.ref.ptr.vec->rec = 0;
|
||||
PTR(r).vec->rec = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNewHash(struct Context* c)
|
||||
{
|
||||
naRef r = naNew(c, T_HASH);
|
||||
r.ref.ptr.hash->rec = 0;
|
||||
PTR(r).hash->rec = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -106,59 +105,57 @@ naRef naNewCode(struct Context* c)
|
||||
naRef naNewCCode(struct Context* c, naCFunction fptr)
|
||||
{
|
||||
naRef r = naNew(c, T_CCODE);
|
||||
r.ref.ptr.ccode->fptr = fptr;
|
||||
PTR(r).ccode->fptr = fptr;
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNewFunc(struct Context* c, naRef code)
|
||||
{
|
||||
naRef func = naNew(c, T_FUNC);
|
||||
func.ref.ptr.func->code = code;
|
||||
func.ref.ptr.func->namespace = naNil();
|
||||
func.ref.ptr.func->next = naNil();
|
||||
PTR(func).func->code = code;
|
||||
PTR(func).func->namespace = naNil();
|
||||
PTR(func).func->next = naNil();
|
||||
return func;
|
||||
}
|
||||
|
||||
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
|
||||
{
|
||||
naRef ghost = naNew(c, T_GHOST);
|
||||
ghost.ref.ptr.ghost->gtype = type;
|
||||
ghost.ref.ptr.ghost->ptr = ptr;
|
||||
PTR(ghost).ghost->gtype = type;
|
||||
PTR(ghost).ghost->ptr = ptr;
|
||||
return ghost;
|
||||
}
|
||||
|
||||
naGhostType* naGhost_type(naRef ghost)
|
||||
{
|
||||
if(!IS_GHOST(ghost)) return 0;
|
||||
return ghost.ref.ptr.ghost->gtype;
|
||||
return PTR(ghost).ghost->gtype;
|
||||
}
|
||||
|
||||
void* naGhost_ptr(naRef ghost)
|
||||
{
|
||||
if(!IS_GHOST(ghost)) return 0;
|
||||
return ghost.ref.ptr.ghost->ptr;
|
||||
return PTR(ghost).ghost->ptr;
|
||||
}
|
||||
|
||||
naRef naNil()
|
||||
{
|
||||
naRef r;
|
||||
r.ref.reftag = NASAL_REFTAG;
|
||||
r.ref.ptr.obj = 0;
|
||||
naRef r;
|
||||
SETPTR(r, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
naRef naNum(double num)
|
||||
{
|
||||
naRef r;
|
||||
r.ref.reftag = ~NASAL_REFTAG;
|
||||
r.num = num;
|
||||
SETNUM(r, num);
|
||||
return r;
|
||||
}
|
||||
|
||||
int naEqual(naRef a, naRef b)
|
||||
{
|
||||
double na=0, nb=0;
|
||||
if(IS_REF(a) && IS_REF(b) && a.ref.ptr.obj == b.ref.ptr.obj)
|
||||
if(IS_REF(a) && IS_REF(b) && PTR(a).obj == PTR(b).obj)
|
||||
return 1; // Object identity (and nil == nil)
|
||||
if(IS_NIL(a) || IS_NIL(b))
|
||||
return 0;
|
||||
@@ -182,10 +179,10 @@ int naStrEqual(naRef a, naRef b)
|
||||
int i;
|
||||
if(!(IS_STR(a) && IS_STR(b)))
|
||||
return 0;
|
||||
if(a.ref.ptr.str->len != b.ref.ptr.str->len)
|
||||
if(PTR(a).str->len != PTR(b).str->len)
|
||||
return 0;
|
||||
for(i=0; i<a.ref.ptr.str->len; i++)
|
||||
if(a.ref.ptr.str->data[i] != b.ref.ptr.str->data[i])
|
||||
for(i=0; i<PTR(a).str->len; i++)
|
||||
if(PTR(a).str->data[i] != PTR(b).str->data[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -214,3 +211,24 @@ int naIsFunc(naRef r) { return IS_FUNC(r); }
|
||||
int naIsCode(naRef r) { return IS_CODE(r); }
|
||||
int naIsCCode(naRef r) { return IS_CCODE(r); }
|
||||
int naIsGhost(naRef r) { return IS_GHOST(r); }
|
||||
|
||||
void naSetUserData(naContext c, void* p) { c->userData = p; }
|
||||
void* naGetUserData(naContext c)
|
||||
{
|
||||
if(c->userData) return c->userData;
|
||||
return c->callParent ? naGetUserData(c->callParent) : 0;
|
||||
}
|
||||
|
||||
void naAddSym(naContext c, naRef ns, char *sym, naRef val)
|
||||
{
|
||||
naRef name = naStr_fromdata(naNewString(c), sym, strlen(sym));
|
||||
naHash_set(ns, naInternSymbol(name), val);
|
||||
}
|
||||
|
||||
naRef naGenLib(naContext c, naCFuncItem *fns)
|
||||
{
|
||||
naRef ns = naNewHash(c);
|
||||
for(/**/; fns->name; fns++)
|
||||
naAddSym(c, ns, fns->name, naNewFunc(c, naNewCCode(c, fns->func)));
|
||||
return ns;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef _NAREF_H
|
||||
#define _NAREF_H
|
||||
|
||||
/* Rather than play elaborate and complicated games with
|
||||
* platform-dependent endianness headers, just detect the platforms we
|
||||
* support. This list is simpler and smaller, yet still quite
|
||||
* complete. */
|
||||
#if (defined(__x86_64) && defined(__linux__)) || defined(__sparcv9)
|
||||
/* Win64 and Irix should work with this too, but have not been
|
||||
* tested */
|
||||
# define NASAL_NAN64
|
||||
#elif defined(_M_IX86) || defined(i386) || defined(__x86_64) || \
|
||||
defined(__ia64__) || defined(_M_IA64) || defined(__ARMEL__)
|
||||
# define NASAL_LE
|
||||
#elif defined(__sparc) || defined(__ppc__) ||defined(__PPC) || \
|
||||
defined(__mips) || defined(__ARMEB__)
|
||||
# define NASAL_BE
|
||||
#else
|
||||
# error Unrecognized CPU architecture
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
struct naObj* obj;
|
||||
struct naStr* str;
|
||||
struct naVec* vec;
|
||||
struct naHash* hash;
|
||||
struct naCode* code;
|
||||
struct naFunc* func;
|
||||
struct naCCode* ccode;
|
||||
struct naGhost* ghost;
|
||||
} naPtr;
|
||||
|
||||
#if defined(NASAL_NAN64)
|
||||
|
||||
/* On suppoted 64 bit platforms (those where all memory returned from
|
||||
* naAlloc() is guaranteed to lie between 0 and 2^48-1) we union the
|
||||
* double with the pointer, and use fancy tricks (see data.h) to make
|
||||
* sure all pointers are stored as NaNs. */
|
||||
typedef union { double num; void* ptr; } naRef;
|
||||
|
||||
#elif defined(NASAL_LE) || defined(NASAL_BE)
|
||||
|
||||
/* 32 bit layouts (and 64 bit platforms where we haven't tested the
|
||||
trick above) need endianness-dependent ordering to make sure that
|
||||
the reftag lies in the top bits of the double */
|
||||
#ifdef NASAL_LE
|
||||
typedef struct { naPtr ptr; int reftag; } naRefPart;
|
||||
#else /* NASAL_BE */
|
||||
typedef struct { int reftag; naPtr ptr; } naRefPart;
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
double num;
|
||||
naRefPart ref;
|
||||
} naRef;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _NAREF_H
|
||||
+111
-109
@@ -4,73 +4,17 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#include "naref.h"
|
||||
|
||||
# if (BSD >= 199103)
|
||||
# include <machine/endian.h>
|
||||
# elif defined(__CYGWIN__) || defined(__MINGW32__)
|
||||
# include <sys/param.h>
|
||||
# elif defined(linux)
|
||||
# include <endian.h>
|
||||
# else
|
||||
# ifndef LITTLE_ENDIAN
|
||||
# define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
|
||||
# endif
|
||||
# ifndef BIG_ENDIAN
|
||||
# define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
|
||||
# endif
|
||||
|
||||
# if defined(ultrix) || defined(__alpha__) || defined(__alpha) || \
|
||||
defined(__i386__) || defined(__i486__) || defined(_X86_) || \
|
||||
defined(sun386)
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
# else
|
||||
# define BYTE_ORDER BIG_ENDIAN
|
||||
# endif
|
||||
# endif /* BSD */
|
||||
#endif /* BYTE_ORDER */
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
# include <limits.h>
|
||||
# if (LONG_MAX == 2147483647)
|
||||
# define NASAL_BIG_ENDIAN_32_BIT 1
|
||||
# endif
|
||||
#if __GNUC__ > 2
|
||||
/* This marks the function as having no side effects and depending on
|
||||
* nothing but its arguments, which allows the optimizer to avoid
|
||||
* duplicate calls to naNil(). */
|
||||
#define GCC_PURE __attribute__((__pure__))
|
||||
#else
|
||||
#define GCC_PURE
|
||||
#endif
|
||||
|
||||
// This is a nasal "reference". They are always copied by value, and
|
||||
// contain either a pointer to a garbage-collectable nasal object
|
||||
// (string, vector, hash) or a floating point number. Keeping the
|
||||
// number here is an optimization to prevent the generation of
|
||||
// zillions of tiny "number" object that have to be collected. Note
|
||||
// sneaky hack: on little endian systems, placing reftag after ptr and
|
||||
// putting 1's in the top 13 (except the sign bit) bits makes the
|
||||
// double value a NaN, and thus unmistakable (no actual number can
|
||||
// appear as a reference, and vice versa). Swap the structure order
|
||||
// on 32 bit big-endian systems. On 64 bit sytems of either
|
||||
// endianness, reftag and the double won't be coincident anyway.
|
||||
#define NASAL_REFTAG 0x7ff56789 // == 2,146,789,257 decimal
|
||||
typedef union {
|
||||
double num;
|
||||
struct {
|
||||
#ifdef NASAL_BIG_ENDIAN_32_BIT
|
||||
int reftag; // Big-endian systems need this here!
|
||||
#endif
|
||||
union {
|
||||
struct naObj* obj;
|
||||
struct naStr* str;
|
||||
struct naVec* vec;
|
||||
struct naHash* hash;
|
||||
struct naCode* code;
|
||||
struct naFunc* func;
|
||||
struct naCCode* ccode;
|
||||
struct naGhost* ghost;
|
||||
} ptr;
|
||||
#ifndef NASAL_BIG_ENDIAN_32_BIT
|
||||
int reftag; // Little-endian and 64 bit systems need this here!
|
||||
#endif
|
||||
} ref;
|
||||
} naRef;
|
||||
|
||||
typedef struct Context* naContext;
|
||||
|
||||
// The function signature for an extension function:
|
||||
@@ -80,7 +24,21 @@ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
|
||||
naContext naNewContext();
|
||||
void naFreeContext(naContext c);
|
||||
|
||||
// Save this object in the context, preventing it (and objects
|
||||
// Use this when making a call to a new context "underneath" a
|
||||
// preexisting context on the same stack. It allows stack walking to
|
||||
// see through the boundary, and eliminates the need to release the
|
||||
// mod lock (i.e. must be called with the mod lock held!)
|
||||
naContext naSubContext(naContext super);
|
||||
|
||||
// The naContext supports a user data pointer that can be used to
|
||||
// store data specific to an naCall invocation without exposing it to
|
||||
// Nasal as a ghost. FIXME: this API is semi-dangerous, there is no
|
||||
// provision for sharing it, nor for validating the source or type of
|
||||
// the pointer returned.
|
||||
void naSetUserData(naContext c, void* p);
|
||||
void* naGetUserData(naContext c) GCC_PURE;
|
||||
|
||||
// "Save" this object in the context, preventing it (and objects
|
||||
// referenced by it) from being garbage collected.
|
||||
void naSave(naContext ctx, naRef obj);
|
||||
|
||||
@@ -89,68 +47,98 @@ void naSave(naContext ctx, naRef obj);
|
||||
// temporaries to protect them before passing back into a naCall.
|
||||
void naTempSave(naContext c, naRef r);
|
||||
|
||||
// Parse a buffer in memory into a code object.
|
||||
// Parse a buffer in memory into a code object. The srcFile parameter
|
||||
// is a Nasal string representing the "file" from which the code is
|
||||
// read. The "first line" is typically 1, but is settable for
|
||||
// situations where the Nasal code is embedded in another context with
|
||||
// its own numbering convetions. If an error occurs, returns nil and
|
||||
// sets the errLine pointer to point to the line at fault. The string
|
||||
// representation of the error can be retrieved with naGetError() on
|
||||
// the context.
|
||||
naRef naParseCode(naContext c, naRef srcFile, int firstLine,
|
||||
char* buf, int len, int* errLine);
|
||||
|
||||
// Binds a bare code object (as returned from naParseCode) with a
|
||||
// closure object (a hash) to act as the outer scope / namespace.
|
||||
// FIXME: this API is weak. It should expose the recursive nature of
|
||||
// closures, and allow for extracting the closure and namespace
|
||||
// information from function objects.
|
||||
naRef naBindFunction(naContext ctx, naRef code, naRef closure);
|
||||
|
||||
// Similar, but it binds to the current context's closure (i.e. the
|
||||
// namespace at the top of the current call stack).
|
||||
naRef naBindToContext(naContext ctx, naRef code);
|
||||
|
||||
// Call a code or function object with the specifed arguments "on" the
|
||||
// specified object and using the specified hash for the local
|
||||
// variables. Any of args, obj or locals may be nil.
|
||||
naRef naCall(naContext ctx, naRef func, int argc, naRef* args, naRef obj, naRef locals);
|
||||
// Call a code or function object with the specified arguments "on"
|
||||
// the specified object and using the specified hash for the local
|
||||
// variables. Passing a null args array skips the parameter variables
|
||||
// (e.g. "arg") assignments; to get a zero-length arg instead, pass in
|
||||
// argc==0 and a non-null args vector. The obj or locals parameters
|
||||
// may be nil. Will attempt to acquire the mod lock, so call
|
||||
// naModUnlock() first if the lock is already held.
|
||||
naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
||||
naRef obj, naRef locals);
|
||||
|
||||
// As naCall(), but continues execution at the operation after a
|
||||
// previous die() call or runtime error. Useful to do "yield"
|
||||
// semantics, leaving the context in a condition where it can be
|
||||
// restarted from C code. Cannot be used currently to restart a
|
||||
// failed operation. Will attempt to acquire the mod lock, so call
|
||||
// naModUnlock() first if the lock is already held.
|
||||
naRef naContinue(naContext ctx);
|
||||
|
||||
// Throw an error from the current call stack. This function makes a
|
||||
// longjmp call to a handler in naCall() and DOES NOT RETURN. It is
|
||||
// intended for use in library code that cannot otherwise report an
|
||||
// error via the return value, and MUST be used carefully. If in
|
||||
// doubt, return naNil() as your error condition.
|
||||
void naRuntimeError(naContext ctx, char* msg);
|
||||
// doubt, return naNil() as your error condition. Works like
|
||||
// printf().
|
||||
void naRuntimeError(naContext c, const char* fmt, ...);
|
||||
|
||||
// Call a method on an object (NOTE: func is a function binding, *not*
|
||||
// a code object as returned from naParseCode).
|
||||
naRef naMethod(naContext ctx, naRef func, naRef object);
|
||||
// "Re-throws" a runtime error caught from the subcontext. Acts as a
|
||||
// naRuntimeError() called on the parent context. Does not return.
|
||||
void naRethrowError(naContext subc);
|
||||
|
||||
// Retrieve the specified member from the object, respecting the
|
||||
// "parents" array as for "object.field". Returns zero for missing
|
||||
// fields.
|
||||
int naMember_get(naRef obj, naRef field, naRef* out);
|
||||
int naMember_cget(naRef obj, const char* field, naRef* out);
|
||||
|
||||
// Returns a hash containing functions from the Nasal standard library
|
||||
// Useful for passing as a namespace to an initial function call
|
||||
naRef naStdLib(naContext c);
|
||||
naRef naInit_std(naContext c);
|
||||
|
||||
// Ditto, for other core libraries
|
||||
naRef naMathLib(naContext c);
|
||||
naRef naBitsLib(naContext c);
|
||||
naRef naIOLib(naContext c);
|
||||
naRef naRegexLib(naContext c);
|
||||
naRef naUnixLib(naContext c);
|
||||
naRef naInit_math(naContext c);
|
||||
naRef naInit_bits(naContext c);
|
||||
naRef naInit_io(naContext c);
|
||||
naRef naInit_regex(naContext c);
|
||||
naRef naInit_unix(naContext c);
|
||||
naRef naInit_thread(naContext c);
|
||||
naRef naInit_utf8(naContext c);
|
||||
naRef naInit_sqlite(naContext c);
|
||||
naRef naInit_readline(naContext c);
|
||||
naRef naInit_gtk(naContext ctx);
|
||||
naRef naInit_cairo(naContext ctx);
|
||||
|
||||
// Current line number & error message
|
||||
// Context stack inspection, frame zero is the "top"
|
||||
int naStackDepth(naContext ctx);
|
||||
int naGetLine(naContext ctx, int frame);
|
||||
naRef naGetSourceFile(naContext ctx, int frame);
|
||||
char* naGetError(naContext ctx);
|
||||
|
||||
// Type predicates
|
||||
int naIsNil(naRef r);
|
||||
int naIsNum(naRef r);
|
||||
int naIsString(naRef r);
|
||||
int naIsScalar(naRef r);
|
||||
int naIsVector(naRef r);
|
||||
int naIsHash(naRef r);
|
||||
int naIsCode(naRef r);
|
||||
int naIsFunc(naRef r);
|
||||
int naIsCCode(naRef r);
|
||||
int naIsNil(naRef r) GCC_PURE;
|
||||
int naIsNum(naRef r) GCC_PURE;
|
||||
int naIsString(naRef r) GCC_PURE;
|
||||
int naIsScalar(naRef r) GCC_PURE;
|
||||
int naIsVector(naRef r) GCC_PURE;
|
||||
int naIsHash(naRef r) GCC_PURE;
|
||||
int naIsCode(naRef r) GCC_PURE;
|
||||
int naIsFunc(naRef r) GCC_PURE;
|
||||
int naIsCCode(naRef r) GCC_PURE;
|
||||
|
||||
// Allocators/generators:
|
||||
naRef naNil();
|
||||
naRef naNum(double num);
|
||||
naRef naNil() GCC_PURE;
|
||||
naRef naNum(double num) GCC_PURE;
|
||||
naRef naNewString(naContext c);
|
||||
naRef naNewVector(naContext c);
|
||||
naRef naNewHash(naContext c);
|
||||
@@ -158,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code);
|
||||
naRef naNewCCode(naContext c, naCFunction fptr);
|
||||
|
||||
// Some useful conversion/comparison routines
|
||||
int naEqual(naRef a, naRef b);
|
||||
int naStrEqual(naRef a, naRef b);
|
||||
int naTrue(naRef b);
|
||||
naRef naNumValue(naRef n);
|
||||
int naEqual(naRef a, naRef b) GCC_PURE;
|
||||
int naStrEqual(naRef a, naRef b) GCC_PURE;
|
||||
int naTrue(naRef b) GCC_PURE;
|
||||
naRef naNumValue(naRef n) GCC_PURE;
|
||||
naRef naStringValue(naContext c, naRef n);
|
||||
|
||||
// String utilities:
|
||||
@@ -192,6 +180,7 @@ void naHash_keys(naRef dst, naRef hash);
|
||||
// Ghost utilities:
|
||||
typedef struct naGhostType {
|
||||
void (*destroy)(void* ghost);
|
||||
const char* name;
|
||||
} naGhostType;
|
||||
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
||||
naGhostType* naGhost_type(naRef ghost);
|
||||
@@ -200,18 +189,31 @@ int naIsGhost(naRef r);
|
||||
|
||||
// Acquires a "modification lock" on a context, allowing the C code to
|
||||
// modify Nasal data without fear that such data may be "lost" by the
|
||||
// garbage collector (the C stack is not examined in GC!). This
|
||||
// disallows garbage collection until the current thread can be
|
||||
// blocked. The lock should be acquired whenever modifications to
|
||||
// Nasal objects are made. It need not be acquired when only read
|
||||
// access is needed. It MUST NOT be acquired by naCFunction's, as
|
||||
// those are called with the lock already held; acquiring two locks
|
||||
// for the same thread will cause a deadlock when the GC is invoked.
|
||||
// It should be UNLOCKED by naCFunction's when they are about to do
|
||||
// any long term non-nasal processing and/or blocking I/O.
|
||||
// garbage collector (nasal data the C stack is not examined in GC!).
|
||||
// This disallows garbage collection until the current thread can be
|
||||
// blocked. The lock should be acquired whenever nasal objects are
|
||||
// being modified. It need not be acquired when only read access is
|
||||
// needed, PRESUMING that the Nasal data being read is findable by the
|
||||
// collector (via naSave, for example) and that another Nasal thread
|
||||
// cannot or will not delete the reference to the data. It MUST NOT
|
||||
// be acquired by naCFunction's, as those are called with the lock
|
||||
// already held; acquiring two locks for the same thread will cause a
|
||||
// deadlock when the GC is invoked. It should be UNLOCKED by
|
||||
// naCFunction's when they are about to do any long term non-nasal
|
||||
// processing and/or blocking I/O. Note that naModLock() may need to
|
||||
// block to allow garbage collection to occur, and that garbage
|
||||
// collection by other threads may be blocked until naModUnlock() is
|
||||
// called. It must also be UNLOCKED by threads that hold a lock
|
||||
// already before making a naCall() or naContinue() call -- these
|
||||
// functions will attempt to acquire the lock again.
|
||||
void naModLock();
|
||||
void naModUnlock();
|
||||
|
||||
// Library utilities. Generate namespaces and add symbols.
|
||||
typedef struct { char* name; naCFunction func; } naCFuncItem;
|
||||
naRef naGenLib(naContext c, naCFuncItem *funcs);
|
||||
void naAddSym(naContext c, naRef ns, char *sym, naRef val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
+82
-8
@@ -1,11 +1,10 @@
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "parse.h"
|
||||
|
||||
// Static precedence table, from low (loose binding, do first) to high
|
||||
// (tight binding, do last).
|
||||
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
||||
|
||||
#define MAX_PREC_TOKS 6
|
||||
struct precedence {
|
||||
int toks[MAX_PREC_TOKS];
|
||||
@@ -32,8 +31,10 @@ struct precedence {
|
||||
|
||||
void naParseError(struct Parser* p, char* msg, int line)
|
||||
{
|
||||
// Some errors (e.g. code generation of a null pointer) lack a
|
||||
// line number, so we throw -1 and set the line earlier.
|
||||
if(line > 0) p->errLine = line;
|
||||
p->err = msg;
|
||||
p->errLine = line;
|
||||
longjmp(p->jumpHandle, 1);
|
||||
}
|
||||
|
||||
@@ -205,11 +206,83 @@ static struct Token* emptyToken(struct Parser* p)
|
||||
return t;
|
||||
}
|
||||
|
||||
// Synthesize a curly brace token to wrap token t foward to the end of
|
||||
// "statement". FIXME: unify this with the addNewChild(), which does
|
||||
// very similar stuff.
|
||||
static void embrace(struct Parser* p, struct Token* t)
|
||||
{
|
||||
struct Token *b, *end = t;
|
||||
if(!t) return;
|
||||
while(end->next) {
|
||||
if(end->next->type == TOK_SEMI) {
|
||||
// Slurp up the semi, iff it is followed by an else/elsif,
|
||||
// otherwise leave it in place.
|
||||
if(end->next->next) {
|
||||
if(end->next->next->type == TOK_ELSE) end = end->next;
|
||||
if(end->next->next->type == TOK_ELSIF) end = end->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(end->next->type == TOK_COMMA) break;
|
||||
if(end->next->type == TOK_ELSE) break;
|
||||
if(end->next->type == TOK_ELSIF) break;
|
||||
end = end->next;
|
||||
}
|
||||
b = emptyToken(p);
|
||||
b->type = TOK_LCURL;
|
||||
b->line = t->line;
|
||||
b->parent = t->parent;
|
||||
b->prev = t->prev;
|
||||
b->next = end->next;
|
||||
b->children = t;
|
||||
b->lastChild = end;
|
||||
if(t->prev) t->prev->next = b;
|
||||
else b->parent->children = b;
|
||||
if(end->next) end->next->prev = b;
|
||||
else b->parent->lastChild = b;
|
||||
t->prev = 0;
|
||||
end->next = 0;
|
||||
for(; t; t = t->next)
|
||||
t->parent = b;
|
||||
}
|
||||
|
||||
#define NEXT(t) (t ? t->next : 0)
|
||||
#define TYPE(t) (t ? t->type : -1)
|
||||
|
||||
static void fixBracelessBlocks(struct Parser* p, struct Token* t)
|
||||
{
|
||||
// Find the end, and march *backward*
|
||||
while(t && t->next) t = t->next;
|
||||
for(/**/; t; t=t->prev) {
|
||||
switch(t->type) {
|
||||
case TOK_FOR: case TOK_FOREACH: case TOK_FORINDEX: case TOK_WHILE:
|
||||
case TOK_IF: case TOK_ELSIF:
|
||||
if(TYPE(NEXT(t)) == TOK_LPAR && TYPE(NEXT(NEXT(t))) != TOK_LCURL)
|
||||
embrace(p, t->next->next);
|
||||
break;
|
||||
case TOK_ELSE:
|
||||
if(TYPE(NEXT(t)) != TOK_LCURL)
|
||||
embrace(p, t->next);
|
||||
break;
|
||||
case TOK_FUNC:
|
||||
if(TYPE(NEXT(t)) == TOK_LPAR) {
|
||||
if(TYPE(NEXT(NEXT(t))) != TOK_LCURL)
|
||||
embrace(p, NEXT(NEXT(t)));
|
||||
} else if(TYPE(NEXT(t)) != TOK_LCURL)
|
||||
embrace(p, t->next);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fixes up parenting for obvious parsing situations, like code blocks
|
||||
// being the child of a func keyword, etc...
|
||||
static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
{
|
||||
struct Token *t, *c;
|
||||
fixBracelessBlocks(p, start);
|
||||
t = start;
|
||||
while(t) {
|
||||
switch(t->type) {
|
||||
@@ -287,8 +360,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
addSemi = 1;
|
||||
break;
|
||||
}
|
||||
if(t->next && t->next->type == TOK_SEMI)
|
||||
addSemi = 0; // don't bother if it's already there!
|
||||
if(!t->next || t->next->type == TOK_SEMI || t->next->type == TOK_COMMA)
|
||||
addSemi = 0; // don't bother, no need
|
||||
if(addSemi) {
|
||||
struct Token* semi = emptyToken(p);
|
||||
semi->type = TOK_SEMI;
|
||||
@@ -297,6 +370,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||
semi->prev = t;
|
||||
semi->parent = t->parent;
|
||||
if(semi->next) semi->next->prev = semi;
|
||||
else semi->parent->lastChild = semi;
|
||||
t->next = semi;
|
||||
t = semi; // don't bother checking the new one
|
||||
}
|
||||
@@ -455,6 +529,8 @@ static struct Token* parsePrecedence(struct Parser* p,
|
||||
if(!top)
|
||||
return parsePrecedence(p, start, end, level+1);
|
||||
|
||||
top->rule = rule;
|
||||
|
||||
if(left) {
|
||||
left->next = right;
|
||||
left->prev = 0;
|
||||
@@ -508,7 +584,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
||||
// Catch parser errors here.
|
||||
*errLine = 0;
|
||||
if(setjmp(p.jumpHandle)) {
|
||||
c->error = p.err;
|
||||
strncpy(c->error, p.err, sizeof(c->error));
|
||||
*errLine = p.errLine;
|
||||
return naNil();
|
||||
}
|
||||
@@ -540,5 +616,3 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
||||
|
||||
return codeObj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,11 +19,15 @@ enum {
|
||||
TOK_FORINDEX
|
||||
};
|
||||
|
||||
// Precedence rules
|
||||
enum { PREC_BINARY=1, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
||||
|
||||
struct Token {
|
||||
int type;
|
||||
int line;
|
||||
char* str;
|
||||
int strlen;
|
||||
int rule;
|
||||
double num;
|
||||
struct Token* parent;
|
||||
struct Token* next;
|
||||
@@ -94,6 +98,7 @@ void naParseInit(struct Parser* p);
|
||||
void* naParseAlloc(struct Parser* p, int bytes);
|
||||
void naParseDestroy(struct Parser* p);
|
||||
void naLex(struct Parser* p);
|
||||
int naLexUtf8C(char* s, int len, int* used); /* in utf8lib.c */
|
||||
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist);
|
||||
|
||||
void naParse(struct Parser* p);
|
||||
|
||||
+16
-16
@@ -14,13 +14,13 @@ static int fromnum(double val, unsigned char* s);
|
||||
int naStr_len(naRef s)
|
||||
{
|
||||
if(!IS_STR(s)) return 0;
|
||||
return s.ref.ptr.str->len;
|
||||
return PTR(s).str->len;
|
||||
}
|
||||
|
||||
char* naStr_data(naRef s)
|
||||
{
|
||||
if(!IS_STR(s)) return 0;
|
||||
return (char*)s.ref.ptr.str->data;
|
||||
return (char*)PTR(s).str->data;
|
||||
}
|
||||
|
||||
static void setlen(struct naStr* s, int sz)
|
||||
@@ -33,24 +33,24 @@ static void setlen(struct naStr* s, int sz)
|
||||
|
||||
naRef naStr_buf(naRef dst, int len)
|
||||
{
|
||||
setlen(dst.ref.ptr.str, len);
|
||||
naBZero(dst.ref.ptr.str->data, len);
|
||||
setlen(PTR(dst).str, len);
|
||||
naBZero(PTR(dst).str->data, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
naRef naStr_fromdata(naRef dst, char* data, int len)
|
||||
{
|
||||
if(!IS_STR(dst)) return naNil();
|
||||
setlen(dst.ref.ptr.str, len);
|
||||
memcpy(dst.ref.ptr.str->data, data, len);
|
||||
setlen(PTR(dst).str, len);
|
||||
memcpy(PTR(dst).str->data, data, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
naRef naStr_concat(naRef dest, naRef s1, naRef s2)
|
||||
{
|
||||
struct naStr* dst = dest.ref.ptr.str;
|
||||
struct naStr* a = s1.ref.ptr.str;
|
||||
struct naStr* b = s2.ref.ptr.str;
|
||||
struct naStr* dst = PTR(dest).str;
|
||||
struct naStr* a = PTR(s1).str;
|
||||
struct naStr* b = PTR(s2).str;
|
||||
if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
|
||||
setlen(dst, a->len + b->len);
|
||||
memcpy(dst->data, a->data, a->len);
|
||||
@@ -60,8 +60,8 @@ naRef naStr_concat(naRef dest, naRef s1, naRef s2)
|
||||
|
||||
naRef naStr_substr(naRef dest, naRef str, int start, int len)
|
||||
{
|
||||
struct naStr* dst = dest.ref.ptr.str;
|
||||
struct naStr* s = str.ref.ptr.str;
|
||||
struct naStr* dst = PTR(dest).str;
|
||||
struct naStr* s = PTR(str).str;
|
||||
if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
|
||||
if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
|
||||
setlen(dst, len);
|
||||
@@ -71,8 +71,8 @@ naRef naStr_substr(naRef dest, naRef str, int start, int len)
|
||||
|
||||
int naStr_equal(naRef s1, naRef s2)
|
||||
{
|
||||
struct naStr* a = s1.ref.ptr.str;
|
||||
struct naStr* b = s2.ref.ptr.str;
|
||||
struct naStr* a = PTR(s1).str;
|
||||
struct naStr* b = PTR(s2).str;
|
||||
if(a->data == b->data) return 1;
|
||||
if(a->len != b->len) return 0;
|
||||
if(memcmp(a->data, b->data, a->len) == 0) return 1;
|
||||
@@ -81,7 +81,7 @@ int naStr_equal(naRef s1, naRef s2)
|
||||
|
||||
naRef naStr_fromnum(naRef dest, double num)
|
||||
{
|
||||
struct naStr* dst = dest.ref.ptr.str;
|
||||
struct naStr* dst = PTR(dest).str;
|
||||
unsigned char buf[DIGITS+8];
|
||||
setlen(dst, fromnum(num, buf));
|
||||
memcpy(dst->data, buf, dst->len);
|
||||
@@ -95,13 +95,13 @@ int naStr_parsenum(char* str, int len, double* result)
|
||||
|
||||
int naStr_tonum(naRef str, double* out)
|
||||
{
|
||||
return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, out);
|
||||
return tonum(PTR(str).str->data, PTR(str).str->len, out);
|
||||
}
|
||||
|
||||
int naStr_numeric(naRef str)
|
||||
{
|
||||
double dummy;
|
||||
return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, &dummy);
|
||||
return tonum(PTR(str).str->data, PTR(str).str->len, &dummy);
|
||||
}
|
||||
|
||||
void naStr_gcclean(struct naStr* str)
|
||||
|
||||
@@ -10,6 +10,12 @@ void* naNewLock()
|
||||
return lock;
|
||||
}
|
||||
|
||||
void naFreeLock(void* lock)
|
||||
{
|
||||
pthread_mutex_destroy(lock);
|
||||
naFree(lock);
|
||||
}
|
||||
|
||||
void naLock(void* lock)
|
||||
{
|
||||
pthread_mutex_lock((pthread_mutex_t*)lock);
|
||||
@@ -35,6 +41,14 @@ void* naNewSem()
|
||||
return sem;
|
||||
}
|
||||
|
||||
void naFreeSem(void* p)
|
||||
{
|
||||
struct naSem* sem = p;
|
||||
pthread_mutex_destroy(&sem->lock);
|
||||
pthread_cond_destroy(&sem->cvar);
|
||||
naFree(sem);
|
||||
}
|
||||
|
||||
void naSemDown(void* sh)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
@@ -45,11 +59,11 @@ void naSemDown(void* sh)
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
void naSemUpAll(void* sh, int count)
|
||||
void naSemUp(void* sh, int count)
|
||||
{
|
||||
struct naSem* sem = (struct naSem*)sh;
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
sem->count = count;
|
||||
sem->count += count;
|
||||
pthread_cond_broadcast(&sem->cvar);
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
}
|
||||
|
||||
@@ -13,9 +13,11 @@ void* naNewLock()
|
||||
|
||||
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||
void naUnlock(void* lock) { LeaveCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||
void naFreeLock(void* lock) { free(lock); }
|
||||
void* naNewSem() { return CreateSemaphore(0, 0, MAX_SEM_COUNT, 0); }
|
||||
void naSemDown(void* sem) { WaitForSingleObject((HANDLE)sem, INFINITE); }
|
||||
void naSemUpAll(void* sem, int count) { ReleaseSemaphore(sem, count, 0); }
|
||||
void naSemUp(void* sem, int count) { ReleaseSemaphore(sem, count, 0); }
|
||||
void naFreeSem(void* sem) { ReleaseSemaphore(sem, 1, 0); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "data.h"
|
||||
#include "code.h"
|
||||
|
||||
static void lockDestroy(void* lock) { naFreeLock(lock); }
|
||||
static naGhostType LockType = { lockDestroy };
|
||||
|
||||
static void semDestroy(void* sem) { naFreeSem(sem); }
|
||||
static naGhostType SemType = { semDestroy };
|
||||
|
||||
typedef struct {
|
||||
naContext ctx;
|
||||
naRef func;
|
||||
} ThreadData;
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI threadtop(LPVOID param)
|
||||
#else
|
||||
static void* threadtop(void* param)
|
||||
#endif
|
||||
{
|
||||
ThreadData* td = param;
|
||||
naCall(td->ctx, td->func, 0, 0, naNil(), naNil());
|
||||
naFreeContext(td->ctx);
|
||||
naFree(td);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static naRef f_newthread(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
ThreadData *td;
|
||||
if(argc < 1 || !naIsFunc(args[0]))
|
||||
naRuntimeError(c, "bad/missing argument to newthread");
|
||||
td = naAlloc(sizeof(*td));
|
||||
td->ctx = naNewContext();
|
||||
td->func = args[0];
|
||||
naTempSave(td->ctx, td->func);
|
||||
#ifdef _WIN32
|
||||
CreateThread(0, 0, threadtop, td, 0, 0);
|
||||
#else
|
||||
{ pthread_t t; pthread_create(&t, 0, threadtop, td); }
|
||||
#endif
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_newlock(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return naNewGhost(c, &LockType, naNewLock());
|
||||
}
|
||||
|
||||
static naRef f_lock(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &LockType)
|
||||
naLock(naGhost_ptr(args[0]));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_unlock(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &LockType)
|
||||
naUnlock(naGhost_ptr(args[0]));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_newsem(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
return naNewGhost(c, &SemType, naNewSem());
|
||||
}
|
||||
|
||||
static naRef f_semdown(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &SemType)
|
||||
naSemDown(naGhost_ptr(args[0]));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_semup(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
if(argc > 0 && naGhost_type(args[0]) == &SemType)
|
||||
naSemUp(naGhost_ptr(args[0]), 1);
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "newthread", f_newthread },
|
||||
{ "newlock", f_newlock },
|
||||
{ "lock", f_lock },
|
||||
{ "unlock", f_unlock },
|
||||
{ "newsem", f_newsem },
|
||||
{ "semdown", f_semdown },
|
||||
{ "semup", f_semup },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naInit_thread(naContext c)
|
||||
{
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#include <string.h>
|
||||
#include "nasal.h"
|
||||
#include "parse.h"
|
||||
|
||||
// bytes required to store a given character
|
||||
static int cbytes(unsigned int c)
|
||||
{
|
||||
static const int NB[] = { 0x7f, 0x07ff, 0xffff, 0x001fffff, 0x03ffffff };
|
||||
int i;
|
||||
for(i=0; i<(sizeof(NB)/sizeof(NB[0])) && c>NB[i]; i++) {}
|
||||
return i+1;
|
||||
}
|
||||
|
||||
// Returns a byte with the N high order bits set
|
||||
#define TOPBITS(n) ((unsigned char)(((signed char)0x80)>>((n)-1)))
|
||||
|
||||
// write a utf8 character, return bytes written or zero on error
|
||||
static int writec(unsigned int c, unsigned char* s, int len)
|
||||
{
|
||||
int i, n = cbytes(c);
|
||||
if(len < n) return 0;
|
||||
for(i=n-1; i>0; i--) {
|
||||
s[i] = 0x80 | (c & 0x3f);
|
||||
c >>= 6;
|
||||
}
|
||||
s[0] = (n > 1 ? TOPBITS(n) : 0) | c;
|
||||
return n;
|
||||
}
|
||||
|
||||
// read a utf8 character, or -1 on error.
|
||||
static int readc(unsigned char* s, int len, int* used)
|
||||
{
|
||||
int n, i, c;
|
||||
if(len > 0 && s[0] < 0x80) { *used = 1; return s[0]; }
|
||||
for(n=2; n<7; n++)
|
||||
if((s[0] & TOPBITS(n+1)) == TOPBITS(n))
|
||||
break;
|
||||
if(len < n || n > 6) return -1;
|
||||
c = s[0] & (~TOPBITS(n+1));
|
||||
for(i=1; i<n; i++) {
|
||||
if((s[i] >> 6) != 2) return -1;
|
||||
c = (c << 6) | (s[i] & 0x3f);
|
||||
}
|
||||
if(n != cbytes(c)) return -1;
|
||||
*used = n;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Public symbol used by the parser */
|
||||
int naLexUtf8C(char* s, int len, int* used)
|
||||
{ return readc((void*)s, len, used); }
|
||||
|
||||
static unsigned char* nthchar(unsigned char* s, int n, int* len)
|
||||
{
|
||||
int i, bytes;
|
||||
for(i=0; *len && i<n; i++) {
|
||||
if(readc(s, *len, &bytes) < 0) return 0;
|
||||
s += bytes; *len -= bytes;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static naRef f_chstr(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
int n;
|
||||
naRef ch;
|
||||
unsigned char buf[6];
|
||||
if(argc < 1 || naIsNil(ch=naNumValue(args[0])))
|
||||
naRuntimeError(ctx, "bad/missing argument to utf8.chstr");
|
||||
n = writec((int)ch.num, buf, sizeof(buf));
|
||||
return naStr_fromdata(naNewString(ctx), (void*)buf, n);
|
||||
}
|
||||
|
||||
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
unsigned char* s;
|
||||
int sz=0, n, len;
|
||||
if(argc < 1 || !naIsString(args[0]))
|
||||
naRuntimeError(c, "bad/missing argument to utf8.strc");
|
||||
s = (void*)naStr_data(args[0]);
|
||||
len = naStr_len(args[0]);
|
||||
while(len > 0) {
|
||||
if(readc(s, len, &n) < 0)
|
||||
naRuntimeError(c, "utf8 encoding error in utf8.size");
|
||||
sz++; len -= n; s += n;
|
||||
}
|
||||
return naNum(sz);
|
||||
}
|
||||
|
||||
static naRef f_strc(naContext ctx, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef idx;
|
||||
unsigned char* s;
|
||||
int len, c=0, bytes;
|
||||
if(argc < 2 || !naIsString(args[0]) || naIsNil(idx=naNumValue(args[1])))
|
||||
naRuntimeError(ctx, "bad/missing argument to utf8.strc");
|
||||
len = naStr_len(args[0]);
|
||||
s = nthchar((void*)naStr_data(args[0]), (int)idx.num, &len);
|
||||
if(!s || (c = readc(s, len, &bytes)) < 0)
|
||||
naRuntimeError(ctx, "utf8 encoding error in utf8.strc");
|
||||
return naNum(c);
|
||||
}
|
||||
|
||||
static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef start, end;
|
||||
int len;
|
||||
unsigned char *s, *s2;
|
||||
end = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||
if((argc < 2 || !naIsString(args[0]) || naIsNil(start=naNumValue(args[1])))
|
||||
|| (argc > 2 && naIsNil(end)))
|
||||
naRuntimeError(c, "bad/missing argument to utf8.substr");
|
||||
len = naStr_len(args[0]);
|
||||
if(!(s = nthchar((void*)naStr_data(args[0]), (int)start.num, &len)))
|
||||
naRuntimeError(c, "start index overrun in utf8.substr");
|
||||
if(!naIsNil(end)) {
|
||||
if(!(s2 = nthchar(s, (int)end.num, &len)))
|
||||
naRuntimeError(c, "end index overrun in utf8.substr");
|
||||
len = (int)(s2-s);
|
||||
}
|
||||
return naStr_fromdata(naNewString(c), (void*)s, len);
|
||||
}
|
||||
|
||||
static naRef f_validate(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef result, unkc=naNil();
|
||||
int len, len2, lenout=0, n;
|
||||
unsigned char *s, *s2, *buf;
|
||||
if(argc < 1 || !naIsString(args[0]) ||
|
||||
(argc > 1 && naIsNil(unkc=naNumValue(args[1]))))
|
||||
naRuntimeError(c, "bad/missing argument to utf8.strc");
|
||||
if(naIsNil(unkc)) unkc = naNum('?');
|
||||
len = naStr_len(args[0]);
|
||||
s = (void*)naStr_data(args[0]);
|
||||
len2 = 6*len; // max for ridiculous unkc values
|
||||
s2 = buf = naAlloc(len2);
|
||||
while(len > 0) {
|
||||
int c = readc(s, len, &n);
|
||||
if(c < 0) { c = (int)unkc.num; n = 1; }
|
||||
s += n; len -= n;
|
||||
n = writec(c, s2, len2);
|
||||
s2 += n; len2 -= n; lenout += n;
|
||||
}
|
||||
result = naStr_fromdata(naNewString(c), (char*)buf, lenout);
|
||||
naFree(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
static naCFuncItem funcs[] = {
|
||||
{ "chstr", f_chstr },
|
||||
{ "strc", f_strc },
|
||||
{ "substr", f_substr },
|
||||
{ "size", f_size },
|
||||
{ "validate", f_validate },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
naRef naInit_utf8(naContext c)
|
||||
{
|
||||
return naGenLib(c, funcs);
|
||||
}
|
||||
+11
-12
@@ -13,7 +13,7 @@ static struct VecRec* newvecrec(struct VecRec* old)
|
||||
return vr;
|
||||
}
|
||||
|
||||
static void vecrealloc(struct naVec* v)
|
||||
static void resize(struct naVec* v)
|
||||
{
|
||||
struct VecRec* vr = newvecrec(v->rec);
|
||||
naGC_swapfree((void**)&(v->rec), vr);
|
||||
@@ -28,7 +28,7 @@ void naVec_gcclean(struct naVec* v)
|
||||
naRef naVec_get(naRef v, int i)
|
||||
{
|
||||
if(IS_VEC(v)) {
|
||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(v).vec->rec;
|
||||
if(r) {
|
||||
if(i < 0) i += r->size;
|
||||
if(i >= 0 && i < r->size) return r->array[i];
|
||||
@@ -40,7 +40,7 @@ naRef naVec_get(naRef v, int i)
|
||||
void naVec_set(naRef vec, int i, naRef o)
|
||||
{
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* r = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(vec).vec->rec;
|
||||
if(r && i >= r->size) return;
|
||||
r->array[i] = o;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ void naVec_set(naRef vec, int i, naRef o)
|
||||
int naVec_size(naRef v)
|
||||
{
|
||||
if(IS_VEC(v)) {
|
||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(v).vec->rec;
|
||||
return r ? r->size : 0;
|
||||
}
|
||||
return 0;
|
||||
@@ -58,10 +58,10 @@ int naVec_size(naRef v)
|
||||
int naVec_append(naRef vec, naRef o)
|
||||
{
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* r = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* r = PTR(vec).vec->rec;
|
||||
while(!r || r->size >= r->alloced) {
|
||||
vecrealloc(vec.ref.ptr.vec);
|
||||
r = vec.ref.ptr.vec->rec;
|
||||
resize(PTR(vec).vec);
|
||||
r = PTR(vec).vec->rec;
|
||||
}
|
||||
r->array[r->size] = o;
|
||||
return r->size++;
|
||||
@@ -72,26 +72,25 @@ int naVec_append(naRef vec, naRef o)
|
||||
void naVec_setsize(naRef vec, int sz)
|
||||
{
|
||||
int i;
|
||||
struct VecRec* v = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* v = PTR(vec).vec->rec;
|
||||
struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz);
|
||||
nv->size = sz;
|
||||
nv->alloced = sz;
|
||||
for(i=0; i<sz; i++)
|
||||
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
|
||||
naFree(v);
|
||||
vec.ref.ptr.vec->rec = nv;
|
||||
naGC_swapfree((void**)&(PTR(vec).vec->rec), nv);
|
||||
}
|
||||
|
||||
naRef naVec_removelast(naRef vec)
|
||||
{
|
||||
naRef o;
|
||||
if(IS_VEC(vec)) {
|
||||
struct VecRec* v = vec.ref.ptr.vec->rec;
|
||||
struct VecRec* v = PTR(vec).vec->rec;
|
||||
if(!v || v->size == 0) return naNil();
|
||||
o = v->array[v->size - 1];
|
||||
v->size--;
|
||||
if(v->size < (v->alloced >> 1))
|
||||
vecrealloc(vec.ref.ptr.vec);
|
||||
resize(PTR(vec).vec);
|
||||
return o;
|
||||
}
|
||||
return naNil();
|
||||
|
||||
@@ -65,7 +65,6 @@ SGNotCondition::SGNotCondition (SGCondition * condition)
|
||||
|
||||
SGNotCondition::~SGNotCondition ()
|
||||
{
|
||||
delete _condition;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -86,8 +85,6 @@ SGAndCondition::SGAndCondition ()
|
||||
|
||||
SGAndCondition::~SGAndCondition ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _conditions.size(); i++)
|
||||
delete _conditions[i];
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -119,8 +116,6 @@ SGOrCondition::SGOrCondition ()
|
||||
|
||||
SGOrCondition::~SGOrCondition ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _conditions.size(); i++)
|
||||
delete _conditions[i];
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -398,13 +393,11 @@ SGConditional::SGConditional ()
|
||||
|
||||
SGConditional::~SGConditional ()
|
||||
{
|
||||
delete _condition;
|
||||
}
|
||||
|
||||
void
|
||||
SGConditional::setCondition (SGCondition * condition)
|
||||
{
|
||||
delete _condition;
|
||||
_condition = condition;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -28,7 +29,7 @@
|
||||
*
|
||||
* This class should migrate to somewhere more general.
|
||||
*/
|
||||
class SGCondition
|
||||
class SGCondition : public SGReferenced
|
||||
{
|
||||
public:
|
||||
SGCondition ();
|
||||
@@ -63,12 +64,11 @@ private:
|
||||
class SGNotCondition : public SGCondition
|
||||
{
|
||||
public:
|
||||
// transfer pointer ownership
|
||||
SGNotCondition (SGCondition * condition);
|
||||
virtual ~SGNotCondition ();
|
||||
virtual bool test () const;
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
SGSharedPtr<SGCondition> _condition;
|
||||
};
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
// transfer pointer ownership
|
||||
virtual void addCondition (SGCondition * condition);
|
||||
private:
|
||||
vector<SGCondition *> _conditions;
|
||||
std::vector<SGSharedPtr<SGCondition> > _conditions;
|
||||
};
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
// transfer pointer ownership
|
||||
virtual void addCondition (SGCondition * condition);
|
||||
private:
|
||||
vector<SGCondition *> _conditions;
|
||||
std::vector<SGSharedPtr<SGCondition> > _conditions;
|
||||
};
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
* invoke the test() method whenever it needs to decide whether to
|
||||
* active itself, draw itself, and so on.
|
||||
*/
|
||||
class SGConditional
|
||||
class SGConditional : public SGReferenced
|
||||
{
|
||||
public:
|
||||
SGConditional ();
|
||||
@@ -156,7 +156,7 @@ public:
|
||||
virtual const SGCondition * getCondition () const { return _condition; }
|
||||
virtual bool test () const;
|
||||
private:
|
||||
SGCondition * _condition;
|
||||
SGSharedPtr<SGCondition> _condition;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+84
-36
@@ -595,11 +595,11 @@ void
|
||||
SGPropertyNode::trace_write () const
|
||||
{
|
||||
#if PROPS_STANDALONE
|
||||
cerr << "TRACE: Write node " << getPath () << ", value\""
|
||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||
<< make_string() << '"' << endl;
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
|
||||
<< ", value\"" << make_string() << '"');
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
|
||||
<< ", value \"" << make_string() << '"');
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ SGPropertyNode::trace_read () const
|
||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||
<< make_string() << '"' << endl;
|
||||
#else
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
|
||||
<< ", value \"" << make_string() << '"');
|
||||
#endif
|
||||
}
|
||||
@@ -756,7 +756,13 @@ SGPropertyNode::~SGPropertyNode ()
|
||||
_removedChildren[i]->_parent = 0;
|
||||
delete _path_cache;
|
||||
clearValue();
|
||||
delete _listeners;
|
||||
|
||||
if (_listeners) {
|
||||
vector<SGPropertyChangeListener*>::iterator it;
|
||||
for (it = _listeners->begin(); it != _listeners->end(); ++it)
|
||||
(*it)->unregister_property(this);
|
||||
delete _listeners;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -904,6 +910,22 @@ SGPropertyNode::getChildren (const char * name) const
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove this node and all children from nodes that link to them
|
||||
* in their path cache.
|
||||
*/
|
||||
void
|
||||
SGPropertyNode::remove_from_path_caches ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _children.size(); ++i)
|
||||
_children[i]->remove_from_path_caches();
|
||||
|
||||
for (unsigned int i = 0; i < _linkedNodes.size(); i++)
|
||||
_linkedNodes[i]->erase(this);
|
||||
_linkedNodes.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove child by position.
|
||||
*/
|
||||
@@ -921,8 +943,8 @@ SGPropertyNode::removeChild (int pos, bool keep)
|
||||
if (keep) {
|
||||
_removedChildren.push_back(node);
|
||||
}
|
||||
if (_path_cache)
|
||||
_path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
|
||||
|
||||
node->remove_from_path_caches();
|
||||
node->setAttribute(REMOVED, true);
|
||||
node->clearValue();
|
||||
fireChildRemoved(node);
|
||||
@@ -933,7 +955,7 @@ SGPropertyNode::removeChild (int pos, bool keep)
|
||||
/**
|
||||
* Remove a child node
|
||||
*/
|
||||
SGPropertyNode_ptr
|
||||
SGPropertyNode_ptr
|
||||
SGPropertyNode::removeChild (const char * name, int index, bool keep)
|
||||
{
|
||||
SGPropertyNode_ptr ret;
|
||||
@@ -961,6 +983,24 @@ SGPropertyNode::removeChildren (const char * name, bool keep)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a linked node.
|
||||
*/
|
||||
bool
|
||||
SGPropertyNode::remove_linked_node (hash_table * node)
|
||||
{
|
||||
for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
|
||||
if (_linkedNodes[i] == node) {
|
||||
vector<hash_table *>::iterator it = _linkedNodes.begin();
|
||||
it += i;
|
||||
_linkedNodes.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
SGPropertyNode::getDisplayName (bool simplify) const
|
||||
{
|
||||
@@ -2187,23 +2227,31 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::bucket::erase (const char * key)
|
||||
bool
|
||||
SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < _length; i++) {
|
||||
if (!strcmp(_entries[i]->get_key(), key))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < _length) {
|
||||
for (++i; i < _length; i++) {
|
||||
_entries[i-1] = _entries[i];
|
||||
for (int i = 0; i < _length; i++) {
|
||||
if (_entries[i]->get_value() == node) {
|
||||
delete _entries[i];
|
||||
for (++i; i < _length; i++) {
|
||||
_entries[i-1] = _entries[i];
|
||||
}
|
||||
_length--;
|
||||
return true;
|
||||
}
|
||||
_length--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
|
||||
{
|
||||
for (int i = 0; i < _length; i++) {
|
||||
SGPropertyNode * node = _entries[i]->get_value();
|
||||
if (node)
|
||||
node->remove_linked_node(owner);
|
||||
}
|
||||
}
|
||||
|
||||
SGPropertyNode::hash_table::hash_table ()
|
||||
: _data_length(0),
|
||||
@@ -2213,8 +2261,12 @@ SGPropertyNode::hash_table::hash_table ()
|
||||
|
||||
SGPropertyNode::hash_table::~hash_table ()
|
||||
{
|
||||
for (unsigned int i = 0; i < _data_length; i++)
|
||||
delete _data[i];
|
||||
for (unsigned int i = 0; i < _data_length; i++) {
|
||||
if (_data[i]) {
|
||||
_data[i]->clear(this);
|
||||
delete _data[i];
|
||||
}
|
||||
}
|
||||
delete [] _data;
|
||||
}
|
||||
|
||||
@@ -2248,17 +2300,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
|
||||
}
|
||||
entry * e = _data[index]->get_entry(key, true);
|
||||
e->set_value(value);
|
||||
value->add_linked_node(this);
|
||||
}
|
||||
|
||||
void
|
||||
SGPropertyNode::hash_table::erase (const char * key)
|
||||
bool
|
||||
SGPropertyNode::hash_table::erase (SGPropertyNode * node)
|
||||
{
|
||||
if (_data_length == 0)
|
||||
return;
|
||||
unsigned int index = hashcode(key) % _data_length;
|
||||
if (_data[index] == 0)
|
||||
return;
|
||||
_data[index]->erase(key);
|
||||
for (unsigned int i = 0; i < _data_length; i++)
|
||||
if (_data[i] && _data[i]->erase(node))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
@@ -2280,12 +2332,8 @@ SGPropertyNode::hash_table::hashcode (const char * key)
|
||||
|
||||
SGPropertyChangeListener::~SGPropertyChangeListener ()
|
||||
{
|
||||
// This will come back and remove
|
||||
// the current item each time. Is
|
||||
// that OK?
|
||||
vector<SGPropertyNode *>::iterator it;
|
||||
for (it = _properties.begin(); it != _properties.end(); it++)
|
||||
(*it)->removeChangeListener(this);
|
||||
for (int i = _properties.size() - 1; i >= 0; i--)
|
||||
_properties[i]->removeChangeListener(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+25
-4
@@ -1110,6 +1110,12 @@ public:
|
||||
void removeChangeListener (SGPropertyChangeListener * listener);
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of listeners.
|
||||
*/
|
||||
int nListeners () const { return _listeners ? _listeners->size() : 0; }
|
||||
|
||||
|
||||
/**
|
||||
* Fire a value change event to all listeners.
|
||||
*/
|
||||
@@ -1183,6 +1189,12 @@ private:
|
||||
void trace_write () const;
|
||||
|
||||
|
||||
/**
|
||||
* Remove this node from all nodes that link to it in their path cache.
|
||||
*/
|
||||
void remove_from_path_caches();
|
||||
|
||||
|
||||
class hash_table;
|
||||
|
||||
int _index;
|
||||
@@ -1193,6 +1205,7 @@ private:
|
||||
SGPropertyNode * _parent;
|
||||
vector<SGPropertyNode_ptr> _children;
|
||||
vector<SGPropertyNode_ptr> _removedChildren;
|
||||
vector<hash_table *> _linkedNodes;
|
||||
mutable string _path;
|
||||
mutable string _buffer;
|
||||
hash_table * _path_cache;
|
||||
@@ -1223,9 +1236,16 @@ private:
|
||||
vector <SGPropertyChangeListener *> * _listeners;
|
||||
|
||||
|
||||
/**
|
||||
* Register/unregister node that links to this node in its path cache.
|
||||
*/
|
||||
void add_linked_node (hash_table * node) { _linkedNodes.push_back(node); }
|
||||
bool remove_linked_node (hash_table * node);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A very simple hash table with no remove functionality.
|
||||
* A very simple hash table.
|
||||
*/
|
||||
class hash_table {
|
||||
public:
|
||||
@@ -1243,7 +1263,7 @@ private:
|
||||
void set_value (SGPropertyNode * value);
|
||||
private:
|
||||
string _key;
|
||||
SGSharedPtr<SGPropertyNode> _value;
|
||||
SGSharedPtr<SGPropertyNode> _value;
|
||||
};
|
||||
|
||||
|
||||
@@ -1255,7 +1275,8 @@ private:
|
||||
bucket ();
|
||||
~bucket ();
|
||||
entry * get_entry (const char * key, bool create = false);
|
||||
void erase(const char * key);
|
||||
bool erase (SGPropertyNode * node);
|
||||
void clear (hash_table * owner);
|
||||
private:
|
||||
int _length;
|
||||
entry ** _entries;
|
||||
@@ -1267,7 +1288,7 @@ private:
|
||||
~hash_table ();
|
||||
SGPropertyNode * get (const char * key);
|
||||
void put (const char * key, SGPropertyNode * value);
|
||||
void erase(const char * key);
|
||||
bool erase (SGPropertyNode * node);
|
||||
|
||||
private:
|
||||
unsigned int hashcode (const char * key);
|
||||
|
||||
@@ -229,6 +229,21 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
} catch (sg_io_exception &e) {
|
||||
setException(e);
|
||||
}
|
||||
|
||||
const char *omit = atts.getValue("omit-node");
|
||||
if (omit && !strcmp(omit, "y")) {
|
||||
int nChildren = node->nChildren();
|
||||
for (int i = 0; i < nChildren; i++) {
|
||||
SGPropertyNode *src = node->getChild(i);
|
||||
const char *name = src->getName();
|
||||
int index = st.counters[name];
|
||||
st.counters[name]++;
|
||||
SGPropertyNode *dst = st.node->getChild(name, index, true);
|
||||
copyProperties(src, dst);
|
||||
}
|
||||
st.node->removeChild(node->getName(), node->getIndex(), false);
|
||||
node = st.node;
|
||||
}
|
||||
}
|
||||
|
||||
const char *type = atts.getValue("type");
|
||||
@@ -432,11 +447,11 @@ doIndent (ostream &output, int indent)
|
||||
|
||||
|
||||
static void
|
||||
writeAtts (ostream &output, const SGPropertyNode * node)
|
||||
writeAtts (ostream &output, const SGPropertyNode * node, bool forceindex)
|
||||
{
|
||||
int index = node->getIndex();
|
||||
|
||||
if (index != 0)
|
||||
if (index != 0 || forceindex)
|
||||
output << " n=\"" << index << '"';
|
||||
|
||||
#if 0
|
||||
@@ -484,13 +499,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
|
||||
|
||||
const string name = node->getName();
|
||||
int nChildren = node->nChildren();
|
||||
bool node_has_value = false;
|
||||
|
||||
// If there is a literal value,
|
||||
// write it first.
|
||||
if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
|
||||
doIndent(output, indent);
|
||||
output << '<' << name;
|
||||
writeAtts(output, node);
|
||||
writeAtts(output, node, nChildren != 0);
|
||||
if (node->isAlias() && node->getAliasTarget() != 0) {
|
||||
output << " alias=\"" << node->getAliasTarget()->getPath()
|
||||
<< "\"/>" << endl;
|
||||
@@ -501,13 +517,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
|
||||
writeData(output, node->getStringValue());
|
||||
output << "</" << name << '>' << endl;
|
||||
}
|
||||
node_has_value = true;
|
||||
}
|
||||
|
||||
// If there are children, write them next.
|
||||
if (nChildren > 0) {
|
||||
doIndent(output, indent);
|
||||
output << '<' << name;
|
||||
writeAtts(output, node);
|
||||
writeAtts(output, node, node_has_value);
|
||||
output << '>' << endl;
|
||||
for (int i = 0; i < nChildren; i++)
|
||||
writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag);
|
||||
@@ -540,6 +557,9 @@ void
|
||||
writeProperties (const string &file, const SGPropertyNode * start_node,
|
||||
bool write_all, SGPropertyNode::Attribute archive_flag)
|
||||
{
|
||||
SGPath path(file.c_str());
|
||||
path.create_dir(0777);
|
||||
|
||||
ofstream output(file.c_str());
|
||||
if (output.good()) {
|
||||
writeProperties(output, start_node, write_all, archive_flag);
|
||||
|
||||
@@ -19,6 +19,9 @@ waytest_LDADD = \
|
||||
$(top_builddir)/simgear/math/libsgmath.a \
|
||||
$(top_builddir)/simgear/debug/libsgdebug.a \
|
||||
$(top_builddir)/simgear/misc/libsgmisc.a \
|
||||
$(top_builddir)/simgear/props/libsgprops.a \
|
||||
$(top_builddir)/simgear/structure/libsgstructure.a \
|
||||
$(top_builddir)/simgear/xml/libsgxml.a \
|
||||
$(base_LIBS) \
|
||||
-lz
|
||||
|
||||
|
||||
+48
-1
@@ -49,7 +49,7 @@ double SGRoute::distance_off_route( double x, double y ) const {
|
||||
int n1 = current_wp;
|
||||
sgdVec3 p, p0, p1, d;
|
||||
sgdSetVec3( p, x, y, 0.0 );
|
||||
sgdSetVec3( p0,
|
||||
sgdSetVec3( p0,
|
||||
route[n0].get_target_lon(), route[n0].get_target_lat(),
|
||||
0.0 );
|
||||
sgdSetVec3( p1,
|
||||
@@ -68,3 +68,50 @@ double SGRoute::distance_off_route( double x, double y ) const {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the length of the leg ending at waypoint index */
|
||||
void SGRoute::update_distance(int index)
|
||||
{
|
||||
SGWayPoint& curr = route[ index ];
|
||||
double course, dist;
|
||||
|
||||
if ( index == 0 ) {
|
||||
dist = 0;
|
||||
} else {
|
||||
const SGWayPoint& prev = route[ index - 1 ];
|
||||
curr.CourseAndDistance( prev, &course, &dist );
|
||||
}
|
||||
|
||||
curr.set_distance( dist );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add waypoint (default), or insert waypoint at position n.
|
||||
* @param wp a waypoint
|
||||
*/
|
||||
void SGRoute::add_waypoint( const SGWayPoint &wp, int n ) {
|
||||
int size = route.size();
|
||||
if ( n < 0 || n >= size ) {
|
||||
n = size;
|
||||
route.push_back( wp );
|
||||
} else {
|
||||
route.insert( route.begin() + n, 1, wp );
|
||||
// update distance of next leg if not at end of route
|
||||
update_distance( n + 1 );
|
||||
}
|
||||
update_distance( n );
|
||||
}
|
||||
|
||||
/** Delete waypoint with index n (last one if n < 0) */
|
||||
void SGRoute::delete_waypoint( int n ) {
|
||||
int size = route.size();
|
||||
if ( size == 0 )
|
||||
return;
|
||||
if ( n < 0 || n >= size )
|
||||
n = size - 1;
|
||||
|
||||
route.erase( route.begin() + n );
|
||||
// update distance of next leg if not at end of route
|
||||
if ( n < size - 1 )
|
||||
update_distance( n );
|
||||
}
|
||||
|
||||
+8
-18
@@ -55,6 +55,8 @@ private:
|
||||
route_list route;
|
||||
int current_wp;
|
||||
|
||||
void update_distance(int index);
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
@@ -70,21 +72,10 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a waypoint.
|
||||
* Add waypoint (default), or insert waypoint at position n.
|
||||
* @param wp a waypoint
|
||||
*/
|
||||
inline void add_waypoint( const SGWayPoint &wp ) {
|
||||
route.push_back( wp );
|
||||
|
||||
int size = route.size();
|
||||
if ( size > 1 ) {
|
||||
SGWayPoint next_to_last = route[ size - 2 ];
|
||||
double tmpd, tmpc;
|
||||
wp.CourseAndDistance( next_to_last, &tmpc, &tmpd );
|
||||
route[size - 1].set_distance( tmpd );
|
||||
}
|
||||
}
|
||||
|
||||
void add_waypoint( const SGWayPoint &wp, int n = -1 );
|
||||
/**
|
||||
* Get the number of waypoints (i.e. route length )
|
||||
* @return route length
|
||||
@@ -146,11 +137,10 @@ public:
|
||||
}
|
||||
|
||||
/** Delete the front waypoint */
|
||||
inline void delete_first() {
|
||||
if ( route.size() ) {
|
||||
route.erase( route.begin() );
|
||||
}
|
||||
}
|
||||
inline void delete_first() { delete_waypoint(0); }
|
||||
|
||||
/** Delete waypoint waypoint with index n (last one if n < 0) */
|
||||
void delete_waypoint( int n = 0 );
|
||||
|
||||
/**
|
||||
* Calculate perpendicular distance from the current route segment
|
||||
|
||||
@@ -8,8 +8,20 @@
|
||||
|
||||
SG_USING_STD(cout);
|
||||
SG_USING_STD(endl);
|
||||
|
||||
int main() {
|
||||
|
||||
void dump_route(const SGRoute& route, const char* message)
|
||||
{
|
||||
cout << "Route dump: " << message << endl;
|
||||
for (int i = 0; i < route.size(); i++) {
|
||||
const SGWayPoint wp = route.get_waypoint(i);
|
||||
cout << "\t#" << i << " " << wp.get_id() << " (" << wp.get_target_lat()
|
||||
<< ", " << wp.get_target_lon() << ") @" << wp.get_target_alt()
|
||||
<< " dist: " << wp.get_distance() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
SGRoute route;
|
||||
|
||||
route.add_waypoint( SGWayPoint(0, 0, 0, SGWayPoint::CARTESIAN, "Start") );
|
||||
@@ -17,7 +29,8 @@ int main() {
|
||||
route.add_waypoint( SGWayPoint(2, 0, 0, SGWayPoint::CARTESIAN, "2") );
|
||||
route.add_waypoint( SGWayPoint(2, 2, 0, SGWayPoint::CARTESIAN, "3") );
|
||||
route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") );
|
||||
|
||||
|
||||
dump_route(route, "Init");
|
||||
route.set_current( 1 );
|
||||
|
||||
cout << "( 0.5, 0 ) = " << route.distance_off_route( 0.5, 0 ) << endl;
|
||||
@@ -29,5 +42,12 @@ int main() {
|
||||
cout << "( 2, 4 ) = " << route.distance_off_route( 2, 4 ) << endl;
|
||||
cout << "( 2.5, 4 ) = " << route.distance_off_route( 2.5, 4 ) << endl;
|
||||
|
||||
SGWayPoint wp2 = route.get_waypoint(2);
|
||||
route.delete_waypoint(2);
|
||||
dump_route(route, "removed WP2");
|
||||
|
||||
route.add_waypoint(wp2, 3);
|
||||
dump_route(route, "added back WP2 after WP3");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
includedir = @includedir@/scene
|
||||
|
||||
SUBDIRS = material model sky tgdb
|
||||
SUBDIRS = material model sky tgdb util
|
||||
|
||||
# lib_LIBRARIES = libsgscene.a
|
||||
|
||||
|
||||
+134
-41
@@ -37,12 +37,23 @@ SG_USING_STD(map);
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Material>
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/Texture2D>
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
|
||||
#include "mat.hxx"
|
||||
|
||||
static map<string, osg::ref_ptr<osg::Texture2D> > _tex_cache;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and destructor.
|
||||
@@ -53,7 +64,7 @@ SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, cons
|
||||
{
|
||||
init();
|
||||
read_properties( fg_root, props, season );
|
||||
build_ssg_state( false );
|
||||
build_state( false );
|
||||
}
|
||||
|
||||
SGMaterial::SGMaterial( const string &texpath )
|
||||
@@ -63,13 +74,13 @@ SGMaterial::SGMaterial( const string &texpath )
|
||||
_internal_state st( NULL, texpath, false );
|
||||
_status.push_back( st );
|
||||
|
||||
build_ssg_state( true );
|
||||
build_state( true );
|
||||
}
|
||||
|
||||
SGMaterial::SGMaterial( ssgSimpleState *s )
|
||||
SGMaterial::SGMaterial( osg::StateSet *s )
|
||||
{
|
||||
init();
|
||||
set_ssg_state( s );
|
||||
set_state( s );
|
||||
}
|
||||
|
||||
SGMaterial::~SGMaterial (void)
|
||||
@@ -120,6 +131,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
string tname = "unknown.rgb";
|
||||
SGPath tpath( fg_root );
|
||||
tpath.append("Textures");
|
||||
tpath.append("Terrain");
|
||||
tpath.append(tname);
|
||||
_internal_state st( NULL, tpath.str(), true );
|
||||
_status.push_back( st );
|
||||
@@ -132,6 +144,13 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
mipmap = props->getBoolValue("mipmap", true);
|
||||
light_coverage = props->getDoubleValue("light-coverage", 0.0);
|
||||
|
||||
// surface values for use with ground reactions
|
||||
solid = props->getBoolValue("solid", true);
|
||||
friction_factor = props->getDoubleValue("friction-factor", 1.0);
|
||||
rolling_friction = props->getDoubleValue("rolling-friction", 0.02);
|
||||
bumpiness = props->getDoubleValue("bumpiness", 0.0);
|
||||
load_resistance = props->getDoubleValue("load-resistance", 1e30);
|
||||
|
||||
// Taken from default values as used in ac3d
|
||||
ambient[0] = props->getDoubleValue("ambient/r", 0.2);
|
||||
ambient[1] = props->getDoubleValue("ambient/g", 0.2);
|
||||
@@ -159,6 +178,14 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
||||
((SGPropertyNode *)props)->getChildren("object-group");
|
||||
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
|
||||
object_groups.push_back(new SGMatModelGroup(object_group_nodes[i]));
|
||||
|
||||
// read glyph table for taxi-/runway-signs
|
||||
vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
|
||||
for (unsigned int i = 0; i < glyph_nodes.size(); i++) {
|
||||
const char *name = glyph_nodes[i]->getStringValue("name");
|
||||
if (name)
|
||||
glyphs[name] = new SGMaterialGlyph(glyph_nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,8 +203,16 @@ SGMaterial::init ()
|
||||
ysize = 0;
|
||||
wrapu = true;
|
||||
wrapv = true;
|
||||
|
||||
mipmap = true;
|
||||
light_coverage = 0.0;
|
||||
|
||||
solid = true;
|
||||
friction_factor = 1;
|
||||
rolling_friction = 0.02;
|
||||
bumpiness = 0;
|
||||
load_resistance = 1e30;
|
||||
|
||||
shininess = 1.0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ambient[i] = (i < 3) ? 0.2 : 1.0;
|
||||
@@ -198,16 +233,15 @@ SGMaterial::load_texture ( int n )
|
||||
if ( !_status[i].texture_loaded ) {
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
|
||||
<< _status[i].texture_path );
|
||||
_status[i].state->setTexture(
|
||||
(char *)_status[i].texture_path.c_str(),
|
||||
wrapu, wrapv, mipmap );
|
||||
assignTexture(_status[i].state.get(), _status[i].texture_path,
|
||||
wrapu, wrapv, mipmap);
|
||||
_status[i].texture_loaded = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ssgSimpleState *
|
||||
osg::StateSet *
|
||||
SGMaterial::get_state (int n) const
|
||||
{
|
||||
if (_status.size() == 0) {
|
||||
@@ -215,65 +249,124 @@ SGMaterial::get_state (int n) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssgSimpleState *st = (n >= 0) ? _status[n].state
|
||||
: _status[_current_ptr].state;
|
||||
((SGMaterial *)this)->_current_ptr += 1;
|
||||
osg::StateSet *st = (n >= 0) ? _status[n].state.get()
|
||||
: _status[_current_ptr].state.get();
|
||||
_current_ptr += 1;
|
||||
if (_current_ptr >= _status.size())
|
||||
((SGMaterial *)this)->_current_ptr = 0;
|
||||
_current_ptr = 0;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SGMaterial::build_ssg_state( bool defer_tex_load )
|
||||
SGMaterial::build_state( bool defer_tex_load )
|
||||
{
|
||||
GLenum shade_model = GL_SMOOTH;
|
||||
|
||||
for (unsigned int i = 0; i < _status.size(); i++)
|
||||
{
|
||||
ssgSimpleState *state = new ssgSimpleState();
|
||||
osg::StateSet *stateSet = new osg::StateSet;
|
||||
stateSet->setUserData(new SGMaterialUserData(this));
|
||||
|
||||
// Set up the textured state
|
||||
state->setShadeModel( shade_model );
|
||||
state->enable( GL_LIGHTING );
|
||||
state->enable ( GL_CULL_FACE ) ;
|
||||
state->enable( GL_TEXTURE_2D );
|
||||
state->disable( GL_BLEND );
|
||||
state->disable( GL_ALPHA_TEST );
|
||||
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
||||
shadeModel->setMode(osg::ShadeModel::SMOOTH);
|
||||
stateSet->setAttribute(shadeModel);
|
||||
|
||||
osg::CullFace* cullFace = new osg::CullFace;
|
||||
cullFace->setMode(osg::CullFace::BACK);
|
||||
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
||||
stateSet->setAttribute(cullFace);
|
||||
|
||||
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
||||
|
||||
if ( !defer_tex_load ) {
|
||||
SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path );
|
||||
state->setTexture( (char *)_status[i].texture_path.c_str(),
|
||||
wrapu, wrapv );
|
||||
assignTexture( stateSet, _status[i].texture_path, wrapu, wrapv);
|
||||
_status[i].texture_loaded = true;
|
||||
} else {
|
||||
_status[i].texture_loaded = false;
|
||||
}
|
||||
|
||||
state->enable( GL_COLOR_MATERIAL );
|
||||
state->setMaterial ( GL_AMBIENT,
|
||||
ambient[0], ambient[1],
|
||||
ambient[2], ambient[3] ) ;
|
||||
state->setMaterial ( GL_DIFFUSE,
|
||||
diffuse[0], diffuse[1],
|
||||
diffuse[2], diffuse[3] ) ;
|
||||
state->setMaterial ( GL_SPECULAR,
|
||||
specular[0], specular[1],
|
||||
specular[2], specular[3] ) ;
|
||||
state->setMaterial ( GL_EMISSION,
|
||||
emission[0], emission[1],
|
||||
emission[2], emission[3] ) ;
|
||||
state->setShininess ( shininess );
|
||||
osg::Material* material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
|
||||
material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
|
||||
material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
|
||||
material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
|
||||
material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
|
||||
stateSet->setAttribute(material);
|
||||
|
||||
_status[i].state = state;
|
||||
if (ambient[3] < 1 || diffuse[3] < 1 ||
|
||||
specular[3] < 1 || emission[3] < 1) {
|
||||
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
|
||||
} else {
|
||||
stateSet->setRenderingHint(osg::StateSet::OPAQUE_BIN);
|
||||
stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
|
||||
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
_status[i].state = stateSet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SGMaterial::set_ssg_state( ssgSimpleState *s )
|
||||
void SGMaterial::set_state( osg::StateSet *s )
|
||||
{
|
||||
_status.push_back( _internal_state( s, "", true ) );
|
||||
}
|
||||
|
||||
// end of mat.cxx
|
||||
void SGMaterial::assignTexture( osg::StateSet *state, const std::string &fname,
|
||||
int _wrapu, int _wrapv, int _mipmap )
|
||||
{
|
||||
map<string, osg::ref_ptr<osg::Texture2D> >::iterator _tex_cache_iter;
|
||||
_tex_cache_iter = _tex_cache.find(fname);
|
||||
if (_tex_cache_iter == _tex_cache.end())
|
||||
{
|
||||
osg::Texture2D* texture = SGLoadTexture2D(fname, _wrapu, _wrapv,
|
||||
mipmap ? -1 : 0);
|
||||
texture->setMaxAnisotropy( SGGetTextureFilter());
|
||||
state->setTextureAttributeAndModes(0, texture);
|
||||
_tex_cache[fname] = texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->setTextureAttributeAndModes(0, _tex_cache_iter->second.get());
|
||||
// cout << "Cache hit: " << fname << endl;
|
||||
}
|
||||
osg::TexEnv* texEnv = new osg::TexEnv;
|
||||
texEnv->setMode(osg::TexEnv::MODULATE);
|
||||
state->setTextureAttributeAndModes(0, texEnv);
|
||||
}
|
||||
|
||||
SGMaterialGlyph* SGMaterial::get_glyph (const string& name) const
|
||||
{
|
||||
map<string, SGSharedPtr<SGMaterialGlyph> >::const_iterator it;
|
||||
it = glyphs.find(name);
|
||||
if (it == glyphs.end())
|
||||
return 0;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SGMaterialGlyph.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SGMaterialGlyph::SGMaterialGlyph(SGPropertyNode *p) :
|
||||
_left(p->getDoubleValue("left", 0.0)),
|
||||
_right(p->getDoubleValue("right", 1.0))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SGSetTextureFilter( int max) {
|
||||
SGSceneFeatures::instance()->setTextureFilter( max);
|
||||
}
|
||||
|
||||
int
|
||||
SGGetTextureFilter() {
|
||||
return SGSceneFeatures::instance()->getTextureFilter();
|
||||
}
|
||||
|
||||
+134
-24
@@ -34,20 +34,26 @@
|
||||
|
||||
#include STL_STRING // Standard C++ string library
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/ssgSharedPtr.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||
|
||||
#include "matmodel.hxx"
|
||||
|
||||
SG_USING_STD(string);
|
||||
SG_USING_STD(vector);
|
||||
SG_USING_STD(map);
|
||||
|
||||
|
||||
class SGMaterialGlyph;
|
||||
|
||||
/**
|
||||
* A material in the scene graph.
|
||||
*
|
||||
@@ -86,20 +92,20 @@ public:
|
||||
|
||||
|
||||
/**
|
||||
* Construct a material around an existing SSG state.
|
||||
* Construct a material around an existing state.
|
||||
*
|
||||
* This constructor allows the application to create a custom,
|
||||
* low-level state for the scene graph and wrap a material around
|
||||
* it. Note: the pointer ownership is transferred to the material.
|
||||
*
|
||||
* @param s The SSG state for this material.
|
||||
* @param s The state for this material.
|
||||
*/
|
||||
SGMaterial( ssgSimpleState *s );
|
||||
SGMaterial( osg::StateSet *s );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~SGMaterial( void );
|
||||
~SGMaterial( void );
|
||||
|
||||
|
||||
|
||||
@@ -113,31 +119,30 @@ public:
|
||||
* @return true if the texture loaded, false if it was loaded
|
||||
* already.
|
||||
*/
|
||||
virtual bool load_texture (int n = -1);
|
||||
|
||||
bool load_texture (int n = -1);
|
||||
|
||||
/**
|
||||
* Get the textured state.
|
||||
*/
|
||||
virtual ssgSimpleState *get_state (int n = -1) const;
|
||||
osg::StateSet *get_state (int n = -1) const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of textures assigned to this material.
|
||||
*/
|
||||
virtual inline int get_num() const { return _status.size(); }
|
||||
inline int get_num() const { return _status.size(); }
|
||||
|
||||
|
||||
/**
|
||||
* Get the xsize of the texture, in meters.
|
||||
*/
|
||||
virtual inline double get_xsize() const { return xsize; }
|
||||
inline double get_xsize() const { return xsize; }
|
||||
|
||||
|
||||
/**
|
||||
* Get the ysize of the texture, in meters.
|
||||
*/
|
||||
virtual inline double get_ysize() const { return ysize; }
|
||||
inline double get_ysize() const { return ysize; }
|
||||
|
||||
|
||||
/**
|
||||
@@ -147,22 +152,75 @@ public:
|
||||
*
|
||||
* @return The area (m^2?) covered by each light.
|
||||
*/
|
||||
virtual inline double get_light_coverage () const { return light_coverage; }
|
||||
inline double get_light_coverage () const { return light_coverage; }
|
||||
|
||||
/**
|
||||
* Return if the surface material is solid, if it is not solid, a fluid
|
||||
* can be assumed, that is usually water.
|
||||
*/
|
||||
bool get_solid () const { return solid; }
|
||||
|
||||
/**
|
||||
* Get the friction factor for that material
|
||||
*/
|
||||
double get_friction_factor () const { return friction_factor; }
|
||||
|
||||
/**
|
||||
* Get the rolling friction for that material
|
||||
*/
|
||||
double get_rolling_friction () const { return rolling_friction; }
|
||||
|
||||
/**
|
||||
* Get the bumpines for that material
|
||||
*/
|
||||
double get_bumpiness () const { return bumpiness; }
|
||||
|
||||
/**
|
||||
* Get the load resistance
|
||||
*/
|
||||
double get_load_resistance () const { return load_resistance; }
|
||||
|
||||
/**
|
||||
* Get the list of names for this material
|
||||
*/
|
||||
const vector<string>& get_names() const { return _names; }
|
||||
|
||||
/**
|
||||
* add the given name to the list of names this material is known
|
||||
*/
|
||||
void add_name(const string& name) { _names.push_back(name); }
|
||||
|
||||
/**
|
||||
* Get the number of randomly-placed objects defined for this material.
|
||||
*/
|
||||
virtual int get_object_group_count () const { return object_groups.size(); }
|
||||
|
||||
int get_object_group_count () const { return object_groups.size(); }
|
||||
|
||||
/**
|
||||
* Get a randomly-placed object for this material.
|
||||
*/
|
||||
virtual SGMatModelGroup * get_object_group (int index) const {
|
||||
SGMatModelGroup * get_object_group (int index) const {
|
||||
return object_groups[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return pointer to glyph class, or 0 if it doesn't exist.
|
||||
*/
|
||||
SGMaterialGlyph * get_glyph (const string& name) const;
|
||||
|
||||
void set_light_color(const SGVec4f& color)
|
||||
{ emission = color; }
|
||||
const SGVec4f& get_light_color() const
|
||||
{ return emission; }
|
||||
|
||||
SGVec2f get_tex_coord_scale() const
|
||||
{
|
||||
float tex_width = get_xsize();
|
||||
float tex_height = get_ysize();
|
||||
|
||||
return SGVec2f((0 < tex_width) ? 1000.0f/tex_width : 1.0f,
|
||||
(0 < tex_height) ? 1000.0f/tex_height : 1.0f);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -173,14 +231,14 @@ protected:
|
||||
/**
|
||||
* Initialization method, invoked by all public constructors.
|
||||
*/
|
||||
virtual void init();
|
||||
void init();
|
||||
|
||||
protected:
|
||||
|
||||
struct _internal_state {
|
||||
_internal_state( ssgSimpleState *s, const string &t, bool l )
|
||||
_internal_state( osg::StateSet *s, const string &t, bool l )
|
||||
: state(s), texture_path(t), texture_loaded(l) {}
|
||||
ssgSharedPtr<ssgSimpleState> state;
|
||||
osg::ref_ptr<osg::StateSet> state;
|
||||
string texture_path;
|
||||
bool texture_loaded;
|
||||
};
|
||||
@@ -196,7 +254,7 @@ private:
|
||||
vector<_internal_state> _status;
|
||||
|
||||
// Round-robin counter
|
||||
unsigned int _current_ptr;
|
||||
mutable unsigned int _current_ptr;
|
||||
|
||||
// texture size
|
||||
double xsize, ysize;
|
||||
@@ -210,12 +268,33 @@ private:
|
||||
// coverage of night lighting.
|
||||
double light_coverage;
|
||||
|
||||
// True if the material is solid, false if it is a fluid
|
||||
bool solid;
|
||||
|
||||
// the friction factor of that surface material
|
||||
double friction_factor;
|
||||
|
||||
// the rolling friction of that surface material
|
||||
double rolling_friction;
|
||||
|
||||
// the bumpiness of that surface material
|
||||
double bumpiness;
|
||||
|
||||
// the load resistance of that surface material
|
||||
double load_resistance;
|
||||
|
||||
// material properties
|
||||
sgVec4 ambient, diffuse, specular, emission;
|
||||
SGVec4f ambient, diffuse, specular, emission;
|
||||
double shininess;
|
||||
|
||||
// the list of names for this material. May be empty.
|
||||
vector<string> _names;
|
||||
|
||||
vector<SGSharedPtr<SGMatModelGroup> > object_groups;
|
||||
|
||||
// taxiway-/runway-sign texture elements
|
||||
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Internal constructors and methods.
|
||||
@@ -224,10 +303,41 @@ private:
|
||||
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
|
||||
|
||||
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
|
||||
void build_ssg_state( bool defer_tex_load );
|
||||
void set_ssg_state( ssgSimpleState *s );
|
||||
void build_state( bool defer_tex_load );
|
||||
void set_state( osg::StateSet *s );
|
||||
|
||||
void assignTexture( osg::StateSet *state, const std::string &fname, int _wrapu = TRUE, int _wrapv = TRUE, int _mipmap = TRUE );
|
||||
|
||||
};
|
||||
|
||||
|
||||
class SGMaterialGlyph : public SGReferenced {
|
||||
public:
|
||||
SGMaterialGlyph(SGPropertyNode *);
|
||||
inline double get_left() const { return _left; }
|
||||
inline double get_right() const { return _right; }
|
||||
inline double get_width() const { return _right - _left; }
|
||||
|
||||
protected:
|
||||
double _left;
|
||||
double _right;
|
||||
};
|
||||
|
||||
class SGMaterialUserData : public osg::Referenced {
|
||||
public:
|
||||
SGMaterialUserData(const SGMaterial* material) :
|
||||
mMaterial(material)
|
||||
{}
|
||||
const SGMaterial* getMaterial() const
|
||||
{ return mMaterial; }
|
||||
private:
|
||||
SGSharedPtr<const SGMaterial> mMaterial;
|
||||
};
|
||||
|
||||
void
|
||||
SGSetTextureFilter( int max);
|
||||
|
||||
int
|
||||
SGGetTextureFilter();
|
||||
|
||||
#endif // _SG_MAT_HXX
|
||||
|
||||
@@ -42,10 +42,24 @@
|
||||
#include <string.h>
|
||||
#include STL_STRING
|
||||
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Material>
|
||||
#include <osg/Point>
|
||||
#include <osg/PointSprite>
|
||||
#include <osg/PolygonMode>
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/scene/tgdb/userdata.hxx>
|
||||
|
||||
#include "mat.hxx"
|
||||
|
||||
@@ -54,126 +68,10 @@
|
||||
SG_USING_NAMESPACE(std);
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
// Constructor
|
||||
SGMaterialLib::SGMaterialLib ( void ) {
|
||||
}
|
||||
|
||||
|
||||
#if 0 // debugging infrastructure
|
||||
static int gen_test_light_map() {
|
||||
static const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double dist = sqrt(x*x + y*y);
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
|
||||
// cout << x << "," << y << " " << (int)(dist * 255) << ","
|
||||
// << (int)((1.0 - dist) * 255) << endl;
|
||||
env_map[i][j][0] = (int)(dist * 255);
|
||||
env_map[i][j][1] = (int)((1.0 - dist) * 255);
|
||||
env_map[i][j][2] = 0;
|
||||
env_map[i][j][3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// generate standard colored directional light environment texture map
|
||||
static int gen_standard_dir_light_map( int r, int g, int b, int alpha ) {
|
||||
const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double dist = sqrt(x*x + y*y);
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
double bright = cos( dist * SGD_PI_2 );
|
||||
if ( bright < 0.3 ) { bright = 0.3; }
|
||||
env_map[i][j][0] = r;
|
||||
env_map[i][j][1] = g;
|
||||
env_map[i][j][2] = b;
|
||||
env_map[i][j][3] = (int)(bright * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
|
||||
|
||||
// generate standard colored directional light environment texture map
|
||||
static int gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
|
||||
const int env_tex_res = 32;
|
||||
int half_res = env_tex_res / 2;
|
||||
unsigned char env_map[env_tex_res][env_tex_res][4];
|
||||
GLuint tex_name;
|
||||
|
||||
for ( int i = 0; i < env_tex_res; ++i ) {
|
||||
for ( int j = 0; j < env_tex_res; ++j ) {
|
||||
double x = (i - half_res) / (double)half_res;
|
||||
double y = (j - half_res) / (double)half_res;
|
||||
double tmp = sqrt(x*x + y*y);
|
||||
double dist = tmp * tmp;
|
||||
if ( dist > 1.0 ) { dist = 1.0; }
|
||||
double bright = sin( dist * SGD_PI_2 );
|
||||
if ( bright < 0.2 ) { bright = 0.2; }
|
||||
env_map[i][j][0] = r;
|
||||
env_map[i][j][1] = g;
|
||||
env_map[i][j][2] = b;
|
||||
env_map[i][j][3] = (int)(bright * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
||||
glGenTextures( 1, &tex_name );
|
||||
glBindTexture( GL_TEXTURE_2D, tex_name );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
|
||||
return tex_name;
|
||||
}
|
||||
|
||||
|
||||
// Load a library of material properties
|
||||
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
|
||||
|
||||
@@ -192,13 +90,14 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
|
||||
for (int i = 0; i < nMaterials; i++) {
|
||||
const SGPropertyNode * node = materials.getChild(i);
|
||||
if (!strcmp(node->getName(), "material")) {
|
||||
SGSharedPtr<SGMaterial> m = new SGMaterial( fg_root, node, season );
|
||||
SGSharedPtr<SGMaterial> m = new SGMaterial(fg_root, node, season);
|
||||
|
||||
vector<SGPropertyNode_ptr>names = node->getChildren("name");
|
||||
for ( unsigned int j = 0; j < names.size(); j++ ) {
|
||||
string name = names[j]->getStringValue();
|
||||
// cerr << "Material " << name << endl;
|
||||
matlib[name] = m;
|
||||
m->add_name(name);
|
||||
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
|
||||
<< names[j]->getStringValue() );
|
||||
}
|
||||
@@ -208,263 +107,6 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char
|
||||
}
|
||||
}
|
||||
|
||||
// hard coded ground light state
|
||||
ssgSimpleState *gnd_lights = new ssgSimpleState;
|
||||
gnd_lights->disable( GL_TEXTURE_2D );
|
||||
gnd_lights->enable( GL_CULL_FACE );
|
||||
gnd_lights->enable( GL_COLOR_MATERIAL );
|
||||
gnd_lights->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
|
||||
gnd_lights->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
|
||||
gnd_lights->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
|
||||
gnd_lights->enable( GL_BLEND );
|
||||
gnd_lights->disable( GL_ALPHA_TEST );
|
||||
gnd_lights->disable( GL_LIGHTING );
|
||||
matlib["GROUND_LIGHTS"] = new SGMaterial( gnd_lights );
|
||||
|
||||
GLuint tex_name;
|
||||
|
||||
// hard coded runway white light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 255 );
|
||||
ssgSimpleState *rwy_white_lights = new ssgSimpleState();
|
||||
rwy_white_lights->disable( GL_LIGHTING );
|
||||
rwy_white_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_white_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_white_lights->enable( GL_BLEND );
|
||||
rwy_white_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_white_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_white_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_lights->setTexture( tex_name );
|
||||
matlib["RWY_WHITE_LIGHTS"] = new SGMaterial( rwy_white_lights );
|
||||
// For backwards compatibility ... remove someday
|
||||
matlib["RUNWAY_LIGHTS"] = new SGMaterial( rwy_white_lights );
|
||||
matlib["RWY_LIGHTS"] = new SGMaterial( rwy_white_lights );
|
||||
// end of backwards compatitibilty
|
||||
|
||||
// hard coded runway medium intensity white light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 205 );
|
||||
ssgSimpleState *rwy_white_medium_lights = new ssgSimpleState();
|
||||
rwy_white_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_white_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_white_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_white_medium_lights->enable( GL_BLEND );
|
||||
rwy_white_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_white_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_white_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_medium_lights->setTexture( tex_name );
|
||||
matlib["RWY_WHITE_MEDIUM_LIGHTS"]
|
||||
= new SGMaterial( rwy_white_medium_lights );
|
||||
|
||||
// hard coded runway low intensity white light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 155 );
|
||||
ssgSimpleState *rwy_white_low_lights = new ssgSimpleState();
|
||||
rwy_white_low_lights->disable( GL_LIGHTING );
|
||||
rwy_white_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_white_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_white_low_lights->enable( GL_BLEND );
|
||||
rwy_white_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_white_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_white_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_white_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_white_low_lights->setTexture( tex_name );
|
||||
matlib["RWY_WHITE_LOW_LIGHTS"]
|
||||
= new SGMaterial( rwy_white_low_lights );
|
||||
|
||||
// hard coded runway yellow light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 215, 20, 255 );
|
||||
ssgSimpleState *rwy_yellow_lights = new ssgSimpleState();
|
||||
rwy_yellow_lights->disable( GL_LIGHTING );
|
||||
rwy_yellow_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_yellow_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_yellow_lights->enable( GL_BLEND );
|
||||
rwy_yellow_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_yellow_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_yellow_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_lights->setTexture( tex_name );
|
||||
matlib["RWY_YELLOW_LIGHTS"] = new SGMaterial( rwy_yellow_lights );
|
||||
|
||||
// hard coded runway medium intensity yellow light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 215, 20, 205 );
|
||||
ssgSimpleState *rwy_yellow_medium_lights = new ssgSimpleState();
|
||||
rwy_yellow_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_yellow_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_yellow_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_yellow_medium_lights->enable( GL_BLEND );
|
||||
rwy_yellow_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_yellow_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_medium_lights->setTexture( tex_name );
|
||||
matlib["RWY_YELLOW_MEDIUM_LIGHTS"]
|
||||
= new SGMaterial( rwy_yellow_medium_lights );
|
||||
|
||||
// hard coded runway low intensity yellow light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 215, 20, 155 );
|
||||
ssgSimpleState *rwy_yellow_low_lights = new ssgSimpleState();
|
||||
rwy_yellow_low_lights->disable( GL_LIGHTING );
|
||||
rwy_yellow_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_yellow_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_yellow_low_lights->enable( GL_BLEND );
|
||||
rwy_yellow_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_yellow_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_yellow_low_lights->setTexture( tex_name );
|
||||
matlib["RWY_YELLOW_LOW_LIGHTS"]
|
||||
= new SGMaterial( rwy_yellow_low_lights );
|
||||
|
||||
// hard coded runway red light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 90, 90, 255 );
|
||||
ssgSimpleState *rwy_red_lights = new ssgSimpleState();
|
||||
rwy_red_lights->disable( GL_LIGHTING );
|
||||
rwy_red_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_red_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_red_lights->enable( GL_BLEND );
|
||||
rwy_red_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_red_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_red_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_lights->setTexture( tex_name );
|
||||
matlib["RWY_RED_LIGHTS"]
|
||||
= new SGMaterial( rwy_red_lights );
|
||||
|
||||
// hard coded medium intensity runway red light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 90, 90, 205 );
|
||||
ssgSimpleState *rwy_red_medium_lights = new ssgSimpleState();
|
||||
rwy_red_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_red_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_red_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_red_medium_lights->enable( GL_BLEND );
|
||||
rwy_red_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_red_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_red_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_medium_lights->setTexture( tex_name );
|
||||
matlib["RWY_RED_MEDIUM_LIGHTS"]
|
||||
= new SGMaterial( rwy_red_medium_lights );
|
||||
|
||||
// hard coded low intensity runway red light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 90, 90, 155 );
|
||||
ssgSimpleState *rwy_red_low_lights = new ssgSimpleState();
|
||||
rwy_red_low_lights->disable( GL_LIGHTING );
|
||||
rwy_red_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_red_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_red_low_lights->enable( GL_BLEND );
|
||||
rwy_red_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_red_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_red_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_red_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_red_low_lights->setTexture( tex_name );
|
||||
matlib["RWY_RED_LOW_LIGHTS"]
|
||||
= new SGMaterial( rwy_red_low_lights );
|
||||
|
||||
// hard coded runway green light state
|
||||
tex_name = gen_standard_dir_light_map( 20, 235, 20, 255 );
|
||||
ssgSimpleState *rwy_green_lights = new ssgSimpleState();
|
||||
rwy_green_lights->disable( GL_LIGHTING );
|
||||
rwy_green_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_green_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_green_lights->enable( GL_BLEND );
|
||||
rwy_green_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_green_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_green_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_lights->setTexture( tex_name );
|
||||
matlib["RWY_GREEN_LIGHTS"]
|
||||
= new SGMaterial( rwy_green_lights );
|
||||
|
||||
// hard coded medium intensity runway green light state
|
||||
tex_name = gen_standard_dir_light_map( 20, 235, 20, 205 );
|
||||
ssgSimpleState *rwy_green_medium_lights = new ssgSimpleState();
|
||||
rwy_green_medium_lights->disable( GL_LIGHTING );
|
||||
rwy_green_medium_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_green_medium_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_green_medium_lights->enable( GL_BLEND );
|
||||
rwy_green_medium_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_green_medium_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_green_medium_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_medium_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_medium_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_medium_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_medium_lights->setTexture( tex_name );
|
||||
matlib["RWY_GREEN_MEDIUM_LIGHTS"]
|
||||
= new SGMaterial( rwy_green_medium_lights );
|
||||
|
||||
// hard coded low intensity runway green light state
|
||||
tex_name = gen_standard_dir_light_map( 20, 235, 20, 155 );
|
||||
ssgSimpleState *rwy_green_low_lights = new ssgSimpleState();
|
||||
rwy_green_low_lights->disable( GL_LIGHTING );
|
||||
rwy_green_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_green_low_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_green_low_lights->enable( GL_BLEND );
|
||||
rwy_green_low_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_green_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_green_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_green_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_green_low_lights->setTexture( tex_name );
|
||||
matlib["RWY_GREEN_LOW_LIGHTS"]
|
||||
= new SGMaterial( rwy_green_low_lights );
|
||||
matlib["RWY_GREEN_TAXIWAY_LIGHTS"]
|
||||
= new SGMaterial( rwy_green_low_lights );
|
||||
|
||||
// hard coded low intensity taxiway blue light state
|
||||
tex_name = gen_taxiway_dir_light_map( 90, 90, 235, 205 );
|
||||
ssgSimpleState *taxiway_blue_low_lights = new ssgSimpleState();
|
||||
taxiway_blue_low_lights->disable( GL_LIGHTING );
|
||||
taxiway_blue_low_lights->enable ( GL_CULL_FACE ) ;
|
||||
taxiway_blue_low_lights->enable( GL_TEXTURE_2D );
|
||||
taxiway_blue_low_lights->enable( GL_BLEND );
|
||||
taxiway_blue_low_lights->enable( GL_ALPHA_TEST );
|
||||
taxiway_blue_low_lights->enable( GL_COLOR_MATERIAL );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
taxiway_blue_low_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
taxiway_blue_low_lights->setTexture( tex_name );
|
||||
matlib["RWY_BLUE_TAXIWAY_LIGHTS"]
|
||||
= new SGMaterial( taxiway_blue_low_lights );
|
||||
|
||||
// hard coded runway vasi light state
|
||||
tex_name = gen_standard_dir_light_map( 235, 235, 195, 255 );
|
||||
ssgSimpleState *rwy_vasi_lights = new ssgSimpleState();
|
||||
rwy_vasi_lights->disable( GL_LIGHTING );
|
||||
rwy_vasi_lights->enable ( GL_CULL_FACE ) ;
|
||||
rwy_vasi_lights->enable( GL_TEXTURE_2D );
|
||||
rwy_vasi_lights->enable( GL_BLEND );
|
||||
rwy_vasi_lights->enable( GL_ALPHA_TEST );
|
||||
rwy_vasi_lights->enable( GL_COLOR_MATERIAL );
|
||||
rwy_vasi_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_vasi_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
|
||||
rwy_vasi_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
|
||||
rwy_vasi_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
|
||||
// rwy_vasi_lights->setTexture( gen_vasi_light_map_old() );
|
||||
rwy_vasi_lights->setTexture( tex_name );
|
||||
matlib["RWY_VASI_LIGHTS"] = new SGMaterial( rwy_vasi_lights );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -491,18 +133,20 @@ bool SGMaterialLib::add_item ( const string &mat_name, const string &full_path )
|
||||
<< mat_name << " (" << full_path << ")");
|
||||
|
||||
matlib[mat_name] = new SGMaterial( full_path );
|
||||
matlib[mat_name]->add_name(mat_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Load a library of material properties
|
||||
bool SGMaterialLib::add_item ( const string &mat_name, ssgSimpleState *state )
|
||||
bool SGMaterialLib::add_item ( const string &mat_name, osg::StateSet *state )
|
||||
{
|
||||
matlib[mat_name] = new SGMaterial( state );
|
||||
matlib[mat_name]->add_name(mat_name);
|
||||
|
||||
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
|
||||
<< "ssgSimpleState = " << mat_name );
|
||||
<< "osg::StateSet = " << mat_name );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -538,3 +182,21 @@ void SGMaterialLib::load_next_deferred() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const SGMaterial*
|
||||
SGMaterialLib::findMaterial(const osg::StateSet* stateSet) const
|
||||
{
|
||||
if (!stateSet)
|
||||
return 0;
|
||||
|
||||
const osg::Referenced* base = stateSet->getUserData();
|
||||
if (!base)
|
||||
return 0;
|
||||
|
||||
const SGMaterialUserData* matUserData
|
||||
= dynamic_cast<const SGMaterialUserData*>(base);
|
||||
if (!matUserData)
|
||||
return 0;
|
||||
|
||||
return matUserData->getMaterial();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user