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 \
|
DoxygenMain.cxx \
|
||||||
README.MSVC \
|
README.MSVC \
|
||||||
README.zlib \
|
README.zlib \
|
||||||
projects \
|
projects \
|
||||||
SimGear.dsp \
|
SimGear.dsp \
|
||||||
SimGear.dsw
|
SimGear.dsw
|
||||||
|
|
||||||
|
|||||||
+67
-33
@@ -556,21 +556,6 @@ SOURCE=.\simgear\math\vector.cxx
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin 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
|
SOURCE=.\simgear\math\SGGeodesy.cxx
|
||||||
|
|
||||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||||
@@ -1184,21 +1169,6 @@ SOURCE=.\simgear\scene\model\animation.cxx
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin 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
|
SOURCE=.\simgear\scene\model\location.cxx
|
||||||
|
|
||||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||||
@@ -1244,7 +1214,7 @@ SOURCE=.\simgear\scene\model\modellib.cxx
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\simgear\scene\model\personality.cxx
|
SOURCE=.\simgear\scene\model\persparam.cxx
|
||||||
|
|
||||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||||
|
|
||||||
@@ -1289,7 +1259,7 @@ SOURCE=.\simgear\scene\model\placementtrans.cxx
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\simgear\scene\model\shadowvolume.cxx
|
SOURCE=.\simgear\scene\model\shadanim.cxx
|
||||||
|
|
||||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||||
|
|
||||||
@@ -1304,7 +1274,7 @@ SOURCE=.\simgear\scene\model\shadowvolume.cxx
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\simgear\scene\model\shadanim.cxx
|
SOURCE=.\simgear\scene\model\SGMaterialAnimation.cxx
|
||||||
|
|
||||||
!IF "$(CFG)" == "SimGear - Win32 Release"
|
!IF "$(CFG)" == "SimGear - Win32 Release"
|
||||||
|
|
||||||
@@ -1549,6 +1519,40 @@ SOURCE=.\simgear\scene\tgdb\userdata.cxx
|
|||||||
|
|
||||||
!ENDIF
|
!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 Source File
|
||||||
# End Group
|
# End Group
|
||||||
# Begin Group "Lib_sgscreen"
|
# Begin Group "Lib_sgscreen"
|
||||||
@@ -1805,6 +1809,36 @@ SOURCE=.\simgear\structure\subsystem_mgr.cxx
|
|||||||
|
|
||||||
!ENDIF
|
!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 Source File
|
||||||
# End Group
|
# End Group
|
||||||
# Begin Group "Lib_sgtiming"
|
# Begin Group "Lib_sgtiming"
|
||||||
|
|||||||
@@ -47,6 +47,18 @@ Jean-Francois Doue
|
|||||||
http://www.animats.com/simpleppp/ftp/public_html/topics/developers.html
|
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>
|
Bruce Finney <bfinney@gte.net>
|
||||||
MSVC5 compatibility.
|
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
|
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>
|
Richard Kaszeta <bofh@me.umn.edu>
|
||||||
Contributed screen buffer to ppm screen shot routine.
|
Contributed screen buffer to ppm screen shot routine.
|
||||||
Rich has also helped in the early development of the Flight Gear "altitude
|
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
|
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 Olson http://www.flightgear.org/~curt/
|
||||||
Curt is responsible for overall project and source code management.
|
Curt is responsible for overall project and source code management.
|
||||||
He has his hands in many of the areas.
|
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"
|
EXTRA_DIRS="${EXTRA_DIRS} $with_plib"
|
||||||
fi
|
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
|
dnl Determine an extra directories to add to include/lib search paths
|
||||||
case "${host}" in
|
case "${host}" in
|
||||||
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
|
*-apple-darwin* | *-*-cygwin* | *-*-mingw32*)
|
||||||
@@ -261,10 +269,10 @@ OPENAL_OK="no"
|
|||||||
case "${host}" in
|
case "${host}" in
|
||||||
*-*-cygwin* | *-*-mingw32*)
|
*-*-cygwin* | *-*-mingw32*)
|
||||||
dnl CygWin under Windoze.
|
dnl CygWin under Windoze.
|
||||||
INCLUDES="$INCLUDES -I/usr/local/include"
|
INCLUDES="$INCLUDES -I/usr/local/include/"
|
||||||
LIBS="$LIBS -L/usr/local/lib"
|
LIBS="$LIBS -L/usr/local/lib"
|
||||||
AC_SEARCH_LIBS(alGenBuffers, openal32)
|
AC_SEARCH_LIBS(alGenBuffers, [ openal32 openal ] )
|
||||||
AC_SEARCH_LIBS(alutInit, [ openal32 ALut ] )
|
AC_SEARCH_LIBS(alutInit, [ openal32 ALut alut ] )
|
||||||
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
|
LIBS="$LIBS -lwinmm -ldsound -ldxguid -lole32"
|
||||||
openal_LIBS="$LIBS"
|
openal_LIBS="$LIBS"
|
||||||
OPENAL_OK="$ac_cv_search_alGenBuffers"
|
OPENAL_OK="$ac_cv_search_alGenBuffers"
|
||||||
@@ -430,6 +438,7 @@ AC_CONFIG_FILES([ \
|
|||||||
simgear/scene/model/Makefile \
|
simgear/scene/model/Makefile \
|
||||||
simgear/scene/sky/Makefile \
|
simgear/scene/sky/Makefile \
|
||||||
simgear/scene/tgdb/Makefile \
|
simgear/scene/tgdb/Makefile \
|
||||||
|
simgear/scene/util/Makefile \
|
||||||
simgear/screen/Makefile \
|
simgear/screen/Makefile \
|
||||||
simgear/serial/Makefile \
|
simgear/serial/Makefile \
|
||||||
simgear/sound/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
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../AL/include;"../../../zlib-1.2.3";"../../../Pre-built.2/include""
|
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
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"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="1"
|
RuntimeLibrary="3"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="false"
|
Detect64BitPortabilityProblems="false"
|
||||||
@@ -103,11 +103,11 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="2"
|
Optimization="2"
|
||||||
AdditionalIncludeDirectories="../..;../../..;../../Simgear;../../../AL/include;"../../../zlib-1.2.3";"../../../Pre-built.2/include""
|
AdditionalIncludeDirectories="../..;../../..;$(ProgramFiles)/OpenThreads/include;$(ProgramFiles)/OpenSceneGraph/include;../../Simgear;../../../3rdparty/include"
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ENABLE_THREADS;_CRT_SECURE_NO_DEPRECATE;_CONST_CORRECT_OVERLOADS;NOMINMAX;_USE_MATH_DEFINES"
|
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"
|
StringPooling="true"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
RuntimeLibrary="0"
|
RuntimeLibrary="2"
|
||||||
FloatingPointModel="2"
|
FloatingPointModel="2"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
@@ -215,10 +215,6 @@
|
|||||||
RelativePath="..\..\simgear\magvar\coremag.hxx"
|
RelativePath="..\..\simgear\magvar\coremag.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\simgear\scene\model\custtrans.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\nasal\data.h"
|
RelativePath="..\..\simgear\nasal\data.h"
|
||||||
>
|
>
|
||||||
@@ -247,10 +243,6 @@
|
|||||||
RelativePath="..\..\simgear\screen\extensions.hxx"
|
RelativePath="..\..\simgear\screen\extensions.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\simgear\math\fastmath.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\timing\geocoord.h"
|
RelativePath="..\..\simgear\timing\geocoord.h"
|
||||||
>
|
>
|
||||||
@@ -511,6 +503,26 @@
|
|||||||
RelativePath="..\..\simgear\math\sg_types.hxx"
|
RelativePath="..\..\simgear\math\sg_types.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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
|
<File
|
||||||
RelativePath="..\..\simgear\math\SGGeoc.hxx"
|
RelativePath="..\..\simgear\math\SGGeoc.hxx"
|
||||||
>
|
>
|
||||||
@@ -531,10 +543,18 @@
|
|||||||
RelativePath="..\..\simgear\math\SGLimits.hxx"
|
RelativePath="..\..\simgear\math\SGLimits.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\model\SGMaterialAnimation.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\math\SGMath.hxx"
|
RelativePath="..\..\simgear\math\SGMath.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\math\SGMathFwd.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\math\SGMatrix.hxx"
|
RelativePath="..\..\simgear\math\SGMatrix.hxx"
|
||||||
>
|
>
|
||||||
@@ -543,6 +563,18 @@
|
|||||||
RelativePath="..\..\simgear\math\SGMisc.hxx"
|
RelativePath="..\..\simgear\math\SGMisc.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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
|
<File
|
||||||
RelativePath="..\..\simgear\math\SGQuat.hxx"
|
RelativePath="..\..\simgear\math\SGQuat.hxx"
|
||||||
>
|
>
|
||||||
@@ -555,18 +587,54 @@
|
|||||||
RelativePath="..\..\simgear\structure\SGReferenced.hxx"
|
RelativePath="..\..\simgear\structure\SGReferenced.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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
|
<File
|
||||||
RelativePath="..\..\simgear\structure\SGSharedPtr.hxx"
|
RelativePath="..\..\simgear\structure\SGSharedPtr.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\util\SGStateAttributeVisitor.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\misc\sgstream.hxx"
|
RelativePath="..\..\simgear\misc\sgstream.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\threads\SGThread.hxx"
|
RelativePath="..\..\simgear\threads\SGThread.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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
|
<File
|
||||||
RelativePath="..\..\simgear\math\SGVec3.hxx"
|
RelativePath="..\..\simgear\math\SGVec3.hxx"
|
||||||
>
|
>
|
||||||
@@ -583,20 +651,6 @@
|
|||||||
RelativePath="..\..\simgear\scene\model\shadowvolume.hxx"
|
RelativePath="..\..\simgear\scene\model\shadowvolume.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\simgear\simgear_config.h"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
Description=""
|
|
||||||
CommandLine=""
|
|
||||||
Outputs=""
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\scene\sky\sky.hxx"
|
RelativePath="..\..\simgear\scene\sky\sky.hxx"
|
||||||
>
|
>
|
||||||
@@ -761,6 +815,10 @@
|
|||||||
RelativePath="..\..\simgear\scene\sky\bbcache.cxx"
|
RelativePath="..\..\simgear\scene\sky\bbcache.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\nasal\bitslib.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\ephemeris\celestialBody.cxx"
|
RelativePath="..\..\simgear\ephemeris\celestialBody.cxx"
|
||||||
>
|
>
|
||||||
@@ -793,10 +851,6 @@
|
|||||||
RelativePath="..\..\simgear\magvar\coremag.cxx"
|
RelativePath="..\..\simgear\magvar\coremag.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\simgear\scene\model\custtrans.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\scene\sky\dome.cxx"
|
RelativePath="..\..\simgear\scene\sky\dome.cxx"
|
||||||
>
|
>
|
||||||
@@ -821,10 +875,6 @@
|
|||||||
RelativePath="..\..\simgear\screen\extensions.cxx"
|
RelativePath="..\..\simgear\screen\extensions.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\simgear\math\fastmath.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\nasal\gc.c"
|
RelativePath="..\..\simgear\nasal\gc.c"
|
||||||
>
|
>
|
||||||
@@ -858,11 +908,11 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
|
RelativePath="..\..\simgear\nasal\iolib.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\scene\tgdb\leaf.cxx"
|
RelativePath="..\..\simgear\ephemeris\jupiter.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
@@ -970,7 +1020,7 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\scene\model\personality.cxx"
|
RelativePath="..\..\simgear\scene\model\persparam.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
@@ -1057,18 +1107,70 @@
|
|||||||
RelativePath="..\..\simgear\timing\sg_time.cxx"
|
RelativePath="..\..\simgear\timing\sg_time.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\structure\SGBinding.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\util\SGEnlargeBoundingBox.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\math\SGGeodesy.cxx"
|
RelativePath="..\..\simgear\math\SGGeodesy.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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
|
<File
|
||||||
RelativePath="..\..\simgear\misc\sgstream.cxx"
|
RelativePath="..\..\simgear\misc\sgstream.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\util\SGTextureStateAttributeVisitor.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\threads\SGThread.cxx"
|
RelativePath="..\..\simgear\threads\SGThread.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\model\SGTranslateTransform.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\scene\tgdb\SGVasiDrawable.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\scene\model\shadanim.cxx"
|
RelativePath="..\..\simgear\scene\model\shadanim.cxx"
|
||||||
>
|
>
|
||||||
@@ -1077,10 +1179,6 @@
|
|||||||
RelativePath="..\..\simgear\screen\shader.cpp"
|
RelativePath="..\..\simgear\screen\shader.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\simgear\scene\model\shadowvolume.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\scene\sky\sky.cxx"
|
RelativePath="..\..\simgear\scene\sky\sky.cxx"
|
||||||
>
|
>
|
||||||
@@ -1137,6 +1235,10 @@
|
|||||||
RelativePath="..\..\simgear\nasal\thread-win32.c"
|
RelativePath="..\..\simgear\nasal\thread-win32.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\nasal\threadlib.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\timing\timestamp.cxx"
|
RelativePath="..\..\simgear\timing\timestamp.cxx"
|
||||||
>
|
>
|
||||||
@@ -1157,6 +1259,10 @@
|
|||||||
RelativePath="..\..\simgear\scene\tgdb\userdata.cxx"
|
RelativePath="..\..\simgear\scene\tgdb\userdata.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\simgear\nasal\utf8lib.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\simgear\nasal\vector.c"
|
RelativePath="..\..\simgear\nasal\vector.c"
|
||||||
>
|
>
|
||||||
@@ -1214,6 +1320,28 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</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>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
</Globals>
|
</Globals>
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ endif
|
|||||||
# METAR_DIRS =
|
# METAR_DIRS =
|
||||||
METAR_DIRS = environment
|
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 = \
|
include_HEADERS = \
|
||||||
compiler.h constants.h sg_inlines.h sg_traits.hxx version.h
|
compiler.h constants.h sg_inlines.h sg_traits.hxx version.h
|
||||||
@@ -34,4 +34,4 @@ SUBDIRS = \
|
|||||||
$(SGTHREAD_DIR) \
|
$(SGTHREAD_DIR) \
|
||||||
timing
|
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);
|
set_bucket(dlon, dlat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SGBucket::SGBucket(const SGGeod& geod) {
|
||||||
|
set_bucket(geod);
|
||||||
|
}
|
||||||
|
|
||||||
// create an impossible bucket if false
|
// create an impossible bucket if false
|
||||||
SGBucket::SGBucket(const bool is_good) {
|
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
|
// Set the bucket params for the specified lat and lon
|
||||||
void SGBucket::set_bucket( double *lonlat ) {
|
void SGBucket::set_bucket( double *lonlat ) {
|
||||||
set_bucket( lonlat[0], lonlat[1] );
|
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
|
// Build the path name for this bucket
|
||||||
string SGBucket::gen_base_path() const {
|
string SGBucket::gen_base_path() const {
|
||||||
// long int index;
|
// long int index;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
#ifdef SG_HAVE_STD_INCLUDES
|
#ifdef SG_HAVE_STD_INCLUDES
|
||||||
# include <cmath>
|
# include <cmath>
|
||||||
@@ -133,6 +134,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
SGBucket(const double dlon, const double dlat);
|
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.
|
/** Construct a bucket.
|
||||||
* @param is_good if false, create an invalid bucket. This is
|
* @param is_good if false, create an invalid bucket. This is
|
||||||
* useful * if you are comparing cur_bucket to last_bucket and
|
* useful * if you are comparing cur_bucket to last_bucket and
|
||||||
@@ -146,11 +154,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
SGBucket(const long int bindex);
|
SGBucket(const long int bindex);
|
||||||
|
|
||||||
/**
|
|
||||||
* Default destructor.
|
|
||||||
*/
|
|
||||||
~SGBucket();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset a bucket to represent a new lat and lon
|
* Reset a bucket to represent a new lat and lon
|
||||||
* @param dlon longitude specified in degrees
|
* @param dlon longitude specified in degrees
|
||||||
@@ -165,6 +168,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void set_bucket( double *lonlat );
|
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.
|
* Create an impossible bucket.
|
||||||
* This is useful if you are comparing cur_bucket to last_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.
|
* @return the height of the tile in meters.
|
||||||
*/
|
*/
|
||||||
double get_height_m() const;
|
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.
|
// Informational methods.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -230,6 +230,7 @@
|
|||||||
|
|
||||||
# define isnan _isnan
|
# define isnan _isnan
|
||||||
# define snprintf _snprintf
|
# define snprintf _snprintf
|
||||||
|
# define copysign _copysign
|
||||||
|
|
||||||
# pragma warning(disable: 4786) // identifier was truncated to '255' characters
|
# pragma warning(disable: 4786) // identifier was truncated to '255' characters
|
||||||
# pragma warning(disable: 4244) // conversion from double to float
|
# pragma warning(disable: 4244) // conversion from double to float
|
||||||
|
|||||||
@@ -128,6 +128,12 @@
|
|||||||
/** Knots to Miles per second */
|
/** Knots to Miles per second */
|
||||||
#define SG_KT_TO_MPS 0.5144444444444444444
|
#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 */
|
/** Miles per second to Miles per hour */
|
||||||
#define SG_MPS_TO_MPH 2.2369362920544020312
|
#define SG_MPS_TO_MPH 2.2369362920544020312
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
logstream *global_logstream = NULL;
|
logstream *global_logstream = NULL;
|
||||||
|
|
||||||
bool logbuf::logging_enabled = true;
|
bool logbuf::logging_enabled = true;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
bool logbuf::has_console = true;
|
||||||
|
#endif
|
||||||
sgDebugClass logbuf::logClass = SG_NONE;
|
sgDebugClass logbuf::logClass = SG_NONE;
|
||||||
sgDebugPriority logbuf::logPriority = SG_INFO;
|
sgDebugPriority logbuf::logPriority = SG_INFO;
|
||||||
streambuf* logbuf::sbuf = NULL;
|
streambuf* logbuf::sbuf = NULL;
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
void set_sb( streambuf* sb );
|
void set_sb( streambuf* sb );
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
static void has_no_console() { has_console = false; }
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** sync/flush */
|
/** sync/flush */
|
||||||
@@ -154,6 +158,9 @@ private:
|
|||||||
static streambuf* sbuf;
|
static streambuf* sbuf;
|
||||||
|
|
||||||
static bool logging_enabled;
|
static bool logging_enabled;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
static bool has_console;
|
||||||
|
#endif
|
||||||
static sgDebugClass logClass;
|
static sgDebugClass logClass;
|
||||||
static sgDebugPriority logPriority;
|
static sgDebugPriority logPriority;
|
||||||
|
|
||||||
@@ -184,7 +191,6 @@ inline logbuf::int_type
|
|||||||
logbuf::overflow( int c )
|
logbuf::overflow( int c )
|
||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
static bool has_console = false;
|
|
||||||
if ( logging_enabled ) {
|
if ( logging_enabled ) {
|
||||||
if ( !has_console ) {
|
if ( !has_console ) {
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
* @file metar.cxx
|
* @file metar.cxx
|
||||||
* Interface for encoded Meteorological Aerodrome Reports (METAR).
|
* Interface for encoded Meteorological Aerodrome Reports (METAR).
|
||||||
*/
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <simgear_config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -744,6 +747,14 @@ bool SGMetar::scanSkyCondition()
|
|||||||
int i;
|
int i;
|
||||||
SGMetarCloud cl;
|
SGMetarCloud cl;
|
||||||
|
|
||||||
|
if (!strncmp(m, "//////", 6)) {
|
||||||
|
m += 6;
|
||||||
|
if (!scanBoundary(&m))
|
||||||
|
return false;
|
||||||
|
_m = m;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strncmp(m, "CLR", i = 3) // clear
|
if (!strncmp(m, "CLR", i = 3) // clear
|
||||||
|| !strncmp(m, "SKC", i = 3) // sky clear
|
|| !strncmp(m, "SKC", i = 3) // sky clear
|
||||||
|| !strncmp(m, "NSC", i = 3) // no significant clouds
|
|| !strncmp(m, "NSC", i = 3) // no significant clouds
|
||||||
@@ -833,7 +844,7 @@ bool SGMetar::scanTemperature()
|
|||||||
return false;
|
return false;
|
||||||
if (!scanBoundary(&m)) {
|
if (!scanBoundary(&m)) {
|
||||||
if (!strncmp(m, "XX", 2)) // not spec compliant!
|
if (!strncmp(m, "XX", 2)) // not spec compliant!
|
||||||
m += 2, sign = 0;
|
m += 2, sign = 0, dew = temp;
|
||||||
else {
|
else {
|
||||||
sign = 1;
|
sign = 1;
|
||||||
if (*m == 'M')
|
if (*m == 'M')
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// Visual environment helper class
|
// Visual environment helper class
|
||||||
//
|
//
|
||||||
// Written by Harald JOHNSEN, started April 2005.
|
// 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
|
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||||
//
|
//
|
||||||
@@ -23,7 +26,6 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <plib/sg.h>
|
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <simgear/structure/SGReferenced.hxx>
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
@@ -190,6 +192,8 @@ SGEnviro::SGEnviro() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
SGEnviro::~SGEnviro(void) {
|
SGEnviro::~SGEnviro(void) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
list_of_lightning::iterator iLightning;
|
list_of_lightning::iterator iLightning;
|
||||||
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; iLightning++ ) {
|
||||||
delete (*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) {
|
void SGEnviro::startOfFrame( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double delta_time) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
view_in_cloud = false;
|
view_in_cloud = false;
|
||||||
// ask the impostor cache to do some cleanup
|
// ask the impostor cache to do some cleanup
|
||||||
if(SGNewCloud::cldCache)
|
if(SGNewCloud::cldCache)
|
||||||
@@ -320,13 +326,15 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
void SGEnviro::setLight(sgVec4 adj_fog_color) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
sgCopyVec4( fog_color, adj_fog_color );
|
sgCopyVec4( fog_color, adj_fog_color );
|
||||||
if( false ) {
|
if( false ) {
|
||||||
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
|
// 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
|
// send data to wx radar
|
||||||
// compute turbulence
|
// compute turbulence
|
||||||
// draw precipitation
|
// draw precipitation
|
||||||
@@ -398,9 +406,10 @@ void SGEnviro::callback_cloud(float heading, float alt, float radius, int family
|
|||||||
LWC = 0.29*2.0;
|
LWC = 0.29*2.0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to the list for the wxRadar instrument
|
// add to the list for the wxRadar instrument
|
||||||
if( LWC > 0.0 )
|
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
|
// 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.setlon(last_lon * SG_DEGREES_TO_RADIANS );
|
||||||
orig.setelev(0.0);
|
orig.setelev(0.0);
|
||||||
dist = sgSqrt(dist);
|
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;
|
lon = dest.lon() * SG_RADIANS_TO_DEGREES;
|
||||||
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
lat = dest.lat() * SG_RADIANS_TO_DEGREES;
|
||||||
addLightning( lon, lat, alt );
|
addLightning( lon, lat, alt );
|
||||||
@@ -441,6 +450,8 @@ list_of_SGWxRadarEcho *SGEnviro::get_radar_echo(void) {
|
|||||||
|
|
||||||
// precipitation rendering code
|
// precipitation rendering code
|
||||||
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
void SGEnviro::DrawCone2(float baseRadius, float height, int slices, bool down, double rain_norm, double speed) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
sgVec3 light;
|
sgVec3 light;
|
||||||
sgAddVec3( light, fog_color, min_light );
|
sgAddVec3( light, fog_color, min_light );
|
||||||
float da = SG_PI * 2.0f / (float) slices;
|
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) {
|
void SGEnviro::drawRain(double pitch, double roll, double heading, double hspeed, double rain_norm) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int debug_period = 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) {
|
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_enable_state && rain_norm > 0.0)
|
||||||
if( precipitation_max_alt >= last_alt )
|
if( precipitation_max_alt >= last_alt )
|
||||||
drawRain(pitch, roll, heading, hspeed, rain_norm);
|
drawRain(pitch, roll, heading, hspeed, rain_norm);
|
||||||
@@ -580,6 +595,8 @@ SGLightning::~SGLightning() {
|
|||||||
|
|
||||||
// lightning rendering code
|
// lightning rendering code
|
||||||
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
void SGLightning::lt_build_tree_branch(int tree_nr, Point3D &start, float energy, int nbseg, float segsize) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
|
|
||||||
sgVec3 dir, newdir;
|
sgVec3 dir, newdir;
|
||||||
int nseg = 0;
|
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) {
|
void SGLightning::lt_build(void) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
Point3D top;
|
Point3D top;
|
||||||
nb_tree = 0;
|
nb_tree = 0;
|
||||||
top[PX] = 0 ;
|
top[PX] = 0 ;
|
||||||
@@ -652,6 +671,8 @@ void SGLightning::lt_build(void) {
|
|||||||
|
|
||||||
|
|
||||||
void SGLightning::lt_Render(void) {
|
void SGLightning::lt_Render(void) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
float flash = 0.5;
|
float flash = 0.5;
|
||||||
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
if( fmod(sgEnviro.elapsed_time*100.0, 100.0) > 50.0 )
|
||||||
flash = sg_random() * 0.75f + 0.25f;
|
flash = sg_random() * 0.75f + 0.25f;
|
||||||
@@ -676,10 +697,12 @@ void SGLightning::lt_Render(void) {
|
|||||||
glDisable( GL_FOG );
|
glDisable( GL_FOG );
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
sgMat4 modelview, tmp;
|
sgMat4 modelview, tmp;
|
||||||
ssgGetModelviewMatrix( modelview );
|
// OSGFIXME
|
||||||
|
// ssgGetModelviewMatrix( modelview );
|
||||||
sgCopyMat4( tmp, sgEnviro.transform );
|
sgCopyMat4( tmp, sgEnviro.transform );
|
||||||
sgPostMultMat4( tmp, modelview );
|
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 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 );
|
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 );
|
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++ ) {
|
for( int n = 0 ; n < nb_tree ; n++ ) {
|
||||||
if( lt_tree[n].prev < 0 )
|
if( lt_tree[n].prev < 0 )
|
||||||
@@ -737,6 +760,8 @@ void SGLightning::lt_Render(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
void SGEnviro::addLightning(double lon, double lat, double alt) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
if( lightnings.size() > 10)
|
if( lightnings.size() > 10)
|
||||||
return;
|
return;
|
||||||
SGLightning *lt= new SGLightning(lon, lat, alt);
|
SGLightning *lt= new SGLightning(lon, lat, alt);
|
||||||
@@ -744,6 +769,8 @@ void SGEnviro::addLightning(double lon, double lat, double alt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SGEnviro::drawLightning(void) {
|
void SGEnviro::drawLightning(void) {
|
||||||
|
// OSGFIXME
|
||||||
|
return;
|
||||||
list_of_lightning::iterator iLightning;
|
list_of_lightning::iterator iLightning;
|
||||||
// play 'thunder' for lightning
|
// play 'thunder' for lightning
|
||||||
if( snd_active )
|
if( snd_active )
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// Visual environment helper class
|
// Visual environment helper class
|
||||||
//
|
//
|
||||||
// Written by Harald JOHNSEN, started April 2005.
|
// 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
|
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||||
//
|
//
|
||||||
@@ -22,6 +25,8 @@
|
|||||||
#ifndef _VISUAL_ENVIRO_HXX
|
#ifndef _VISUAL_ENVIRO_HXX
|
||||||
#define _VISUAL_ENVIRO_HXX
|
#define _VISUAL_ENVIRO_HXX
|
||||||
|
|
||||||
|
#include <plib/sg.h>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include STL_STRING
|
#include STL_STRING
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -38,23 +43,32 @@ class SGSoundMgr;
|
|||||||
*/
|
*/
|
||||||
class SGWxRadarEcho {
|
class SGWxRadarEcho {
|
||||||
public:
|
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 ),
|
heading( _heading ),
|
||||||
alt ( _alt ),
|
alt ( _alt ),
|
||||||
radius ( _radius ),
|
radius ( _radius ),
|
||||||
dist ( _dist ),
|
dist ( _dist ),
|
||||||
LWC ( _LWC ),
|
LWC ( _LWC ),
|
||||||
lightning ( _lightning ),
|
lightning ( _lightning ),
|
||||||
|
aircraft ( _aircraft ),
|
||||||
cloudId ( _cloudId )
|
cloudId ( _cloudId )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/** the heading in radian is versus north */
|
/** the heading and bearing in radian are versus north */
|
||||||
float heading;
|
float bearing, heading;
|
||||||
float alt, radius, dist;
|
float alt, radius, dist;
|
||||||
|
|
||||||
/** reflectivity converted to liquid water content. */
|
/** reflectivity converted to liquid water content. */
|
||||||
double LWC;
|
double LWC;
|
||||||
|
|
||||||
/** if true then this data is for a lightning else it is for water echo. */
|
/** if true then this data is for a lightning else it is for water echo. */
|
||||||
bool lightning;
|
bool lightning;
|
||||||
|
|
||||||
|
/** if true then this data is for an aircraft */
|
||||||
|
bool aircraft;
|
||||||
|
|
||||||
/** Unique identifier of cloud */
|
/** Unique identifier of cloud */
|
||||||
int cloudId;
|
int cloudId;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGEphemeris::SGEphemeris( const string &path ) {
|
SGEphemeris::SGEphemeris( const std::string &path ) {
|
||||||
our_sun = new Star;
|
our_sun = new Star;
|
||||||
moon = new MoonPos;
|
moon = new MoonPos;
|
||||||
mercury = new Mercury;
|
mercury = new Mercury;
|
||||||
@@ -42,9 +42,8 @@ SGEphemeris::SGEphemeris( const string &path ) {
|
|||||||
uranus = new Uranus;
|
uranus = new Uranus;
|
||||||
neptune = new Neptune;
|
neptune = new Neptune;
|
||||||
nplanets = 7;
|
nplanets = 7;
|
||||||
for ( int i = 0; i < nplanets; ++i ) {
|
for ( int i = 0; i < nplanets; ++i )
|
||||||
sgdSetVec3( planets[i], 0.0, 0.0, 0.0 );
|
planets[i] = SGVec3d::zeros();
|
||||||
}
|
|
||||||
stars = new SGStarData( SGPath(path) );
|
stars = new SGStarData( SGPath(path) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,7 @@
|
|||||||
#ifndef _EPHEMERIS_HXX
|
#ifndef _EPHEMERIS_HXX
|
||||||
#define _EPHEMERIS_HXX
|
#define _EPHEMERIS_HXX
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <plib/sg.h>
|
|
||||||
|
|
||||||
#include <simgear/ephemeris/star.hxx>
|
#include <simgear/ephemeris/star.hxx>
|
||||||
#include <simgear/ephemeris/moonpos.hxx>
|
#include <simgear/ephemeris/moonpos.hxx>
|
||||||
@@ -43,6 +42,9 @@
|
|||||||
#include <simgear/ephemeris/neptune.hxx>
|
#include <simgear/ephemeris/neptune.hxx>
|
||||||
#include <simgear/ephemeris/stardata.hxx>
|
#include <simgear/ephemeris/stardata.hxx>
|
||||||
|
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
|
|
||||||
/** Ephemeris class
|
/** Ephemeris class
|
||||||
*
|
*
|
||||||
@@ -83,7 +85,7 @@ class SGEphemeris {
|
|||||||
// planets[i][1] = Declination
|
// planets[i][1] = Declination
|
||||||
// planets[i][2] = Magnitude
|
// planets[i][2] = Magnitude
|
||||||
int nplanets;
|
int nplanets;
|
||||||
sgdVec3 planets[7];
|
SGVec3d planets[7];
|
||||||
|
|
||||||
SGStarData *stars;
|
SGStarData *stars;
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ public:
|
|||||||
* calling the constructor you need to provide a path pointing to
|
* calling the constructor you need to provide a path pointing to
|
||||||
* your star database file.
|
* your star database file.
|
||||||
* @param path path to your star database */
|
* @param path path to your star database */
|
||||||
SGEphemeris( const string &path );
|
SGEphemeris( const std::string &path );
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~SGEphemeris( void );
|
~SGEphemeris( void );
|
||||||
@@ -155,7 +157,7 @@ public:
|
|||||||
* the second is the declination, and the third is the magnitude.
|
* the second is the declination, and the third is the magnitude.
|
||||||
* @return planets array
|
* @return planets array
|
||||||
*/
|
*/
|
||||||
inline sgdVec3 *getPlanets() { return planets; }
|
inline SGVec3d *getPlanets() { return planets; }
|
||||||
|
|
||||||
/** @return the numbers of defined stars. */
|
/** @return the numbers of defined stars. */
|
||||||
inline int getNumStars() const { return stars->getNumStars(); }
|
inline int getNumStars() const { return stars->getNumStars(); }
|
||||||
@@ -167,7 +169,7 @@ public:
|
|||||||
* third is the magnitude.
|
* third is the magnitude.
|
||||||
* @returns star array
|
* @returns star array
|
||||||
*/
|
*/
|
||||||
inline sgdVec3 *getStars() { return stars->getStars(); }
|
inline SGVec3d *getStars() { return stars->getStars(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
#include <simgear/misc/sgstream.hxx>
|
||||||
|
|
||||||
#include "stardata.hxx"
|
#include "stardata.hxx"
|
||||||
@@ -34,16 +35,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGStarData::SGStarData() :
|
SGStarData::SGStarData( const SGPath& path )
|
||||||
nstars(0)
|
|
||||||
{
|
{
|
||||||
}
|
load(path);
|
||||||
|
|
||||||
SGStarData::SGStarData( SGPath path ) :
|
|
||||||
nstars(0)
|
|
||||||
{
|
|
||||||
data_path = SGPath( path );
|
|
||||||
load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
_stars.clear();
|
||||||
// array, problem for some compilers
|
|
||||||
stars = new sgdVec3[SG_MAX_STARS];
|
|
||||||
|
|
||||||
// build the full path name to the stars data base file
|
// build the full path name to the stars data base file
|
||||||
data_path.append( "stars" );
|
SGPath tmp = path;
|
||||||
SG_LOG( SG_ASTRO, SG_INFO, " Loading stars from " << data_path.str() );
|
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() ) {
|
if ( ! in.is_open() ) {
|
||||||
SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: "
|
SG_LOG( SG_ASTRO, SG_ALERT, "Cannot open star file: "
|
||||||
<< data_path.str() );
|
<< tmp.str() );
|
||||||
exit(-1);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ra, dec, mag;
|
double ra, dec, mag;
|
||||||
char c;
|
char c;
|
||||||
string name;
|
string name;
|
||||||
|
|
||||||
nstars = 0;
|
|
||||||
|
|
||||||
// read in each line of the file
|
// read in each line of the file
|
||||||
while ( ! in.eof() && nstars < SG_MAX_STARS ) {
|
while ( ! in.eof() ) {
|
||||||
in >> skipcomment;
|
in >> skipcomment;
|
||||||
|
|
||||||
getline( in, name, ',' );
|
getline( in, name, ',' );
|
||||||
@@ -116,13 +107,10 @@ bool SGStarData::load() {
|
|||||||
in >> mag;
|
in >> mag;
|
||||||
|
|
||||||
// cout << " star data = " << ra << " " << dec << " " << mag << endl;
|
// cout << " star data = " << ra << " " << dec << " " << mag << endl;
|
||||||
|
_stars.push_back(SGVec3d(ra, dec, mag));
|
||||||
sgdSetVec3( stars[nstars], ra, dec, mag );
|
|
||||||
|
|
||||||
++nstars;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << nstars << " stars" );
|
SG_LOG( SG_ASTRO, SG_INFO, " Loaded " << _stars.size() << " stars" );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,37 +24,28 @@
|
|||||||
#ifndef _SG_STARDATA_HXX
|
#ifndef _SG_STARDATA_HXX
|
||||||
#define _SG_STARDATA_HXX
|
#define _SG_STARDATA_HXX
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
#include <plib/sg.h>
|
class SGPath;
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
|
|
||||||
#define SG_MAX_STARS 850
|
|
||||||
|
|
||||||
|
|
||||||
class SGStarData {
|
class SGStarData {
|
||||||
|
|
||||||
int nstars;
|
|
||||||
sgdVec3 *stars;
|
|
||||||
|
|
||||||
SGPath data_path;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGStarData();
|
SGStarData( const SGPath& path );
|
||||||
SGStarData( SGPath path );
|
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~SGStarData();
|
~SGStarData();
|
||||||
|
|
||||||
// load the stars database
|
// load the stars database
|
||||||
bool load();
|
bool load( const SGPath& path );
|
||||||
|
|
||||||
// stars
|
// stars
|
||||||
inline int getNumStars() const { return nstars; }
|
inline int getNumStars() const { return _stars.size(); }
|
||||||
inline sgdVec3 *getStars() { return stars; }
|
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());
|
obj.get_gbs_radius());
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
|
||||||
point_list nodes = obj.get_wgs84_nodes();
|
std::vector<SGVec3d> nodes = obj.get_wgs84_nodes();
|
||||||
cout << "# vertex list" << endl;
|
cout << "# vertex list" << endl;
|
||||||
for ( i = 0; i < (int)nodes.size(); ++i ) {
|
for ( i = 0; i < (int)nodes.size(); ++i ) {
|
||||||
printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() );
|
printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() );
|
||||||
}
|
}
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
|
||||||
point_list normals = obj.get_normals();
|
std::vector<SGVec3f> normals = obj.get_normals();
|
||||||
cout << "# vertex normal list" << endl;
|
cout << "# vertex normal list" << endl;
|
||||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
for ( i = 0; i < (int)normals.size(); ++i ) {
|
||||||
printf("vn %.5f %.5f %.5f\n",
|
printf("vn %.5f %.5f %.5f\n",
|
||||||
@@ -52,7 +52,7 @@ int main( int argc, char **argv ) {
|
|||||||
}
|
}
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
|
||||||
point_list texcoords = obj.get_texcoords();
|
std::vector<SGVec2f> texcoords = obj.get_texcoords();
|
||||||
cout << "# texture coordinate list" << endl;
|
cout << "# texture coordinate list" << endl;
|
||||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||||
printf("vt %.5f %.5f\n",
|
printf("vt %.5f %.5f\n",
|
||||||
|
|||||||
+30
-45
@@ -174,7 +174,7 @@ static void read_object( gzFile fp,
|
|||||||
int idx_size;
|
int idx_size;
|
||||||
bool do_vertices, do_normals, do_colors, do_texcoords;
|
bool do_vertices, do_normals, do_colors, do_texcoords;
|
||||||
int j, k, idx;
|
int j, k, idx;
|
||||||
static sgSimpleBuffer buf( 32768 ); // 32 Kb
|
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||||
char material[256];
|
char material[256];
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
@@ -280,13 +280,13 @@ static void read_object( gzFile fp,
|
|||||||
|
|
||||||
// read a binary file and populate the provided structures.
|
// read a binary file and populate the provided structures.
|
||||||
bool SGBinObject::read_bin( const string& file ) {
|
bool SGBinObject::read_bin( const string& file ) {
|
||||||
Point3D p;
|
SGVec3d p;
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
unsigned int nbytes;
|
unsigned int nbytes;
|
||||||
static sgSimpleBuffer buf( 32768 ); // 32 Kb
|
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||||
|
|
||||||
// zero out structures
|
// zero out structures
|
||||||
gbs_center = Point3D( 0 );
|
gbs_center = SGVec3d(0, 0, 0);
|
||||||
gbs_radius = 0.0;
|
gbs_radius = 0.0;
|
||||||
|
|
||||||
wgs84_nodes.clear();
|
wgs84_nodes.clear();
|
||||||
@@ -322,7 +322,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
string filegz = file + ".gz";
|
string filegz = file + ".gz";
|
||||||
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
|
if ( (fp = gzopen( filegz.c_str(), "rb" )) == NULL ) {
|
||||||
SG_LOG( SG_EVENT, SG_ALERT,
|
SG_LOG( SG_EVENT, SG_ALERT,
|
||||||
"ERROR: opening " << file << " or " << filegz << "for reading!");
|
"ERROR: opening " << file << " or " << filegz << " for reading!");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -407,7 +407,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
sgEndianSwap( (uint64_t *)&(dptr[1]) );
|
sgEndianSwap( (uint64_t *)&(dptr[1]) );
|
||||||
sgEndianSwap( (uint64_t *)&(dptr[2]) );
|
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;
|
// cout << "Center = " << gbs_center << endl;
|
||||||
ptr += sizeof(double) * 3;
|
ptr += sizeof(double) * 3;
|
||||||
|
|
||||||
@@ -447,7 +447,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
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;
|
fptr += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -481,7 +481,8 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
sgEndianSwap( (uint32_t *)&(fptr[2]) );
|
||||||
sgEndianSwap( (uint32_t *)&(fptr[3]) );
|
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;
|
fptr += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,14 +509,11 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
int count = nbytes / 3;
|
int count = nbytes / 3;
|
||||||
normals.reserve( count );
|
normals.reserve( count );
|
||||||
for ( k = 0; k < count; ++k ) {
|
for ( k = 0; k < count; ++k ) {
|
||||||
sgdVec3 normal;
|
SGVec3f normal((ptr[0]) / 127.5 - 1.0,
|
||||||
sgdSetVec3( normal,
|
(ptr[1]) / 127.5 - 1.0,
|
||||||
(ptr[0]) / 127.5 - 1.0,
|
(ptr[2]) / 127.5 - 1.0);
|
||||||
(ptr[1]) / 127.5 - 1.0,
|
|
||||||
(ptr[2]) / 127.5 - 1.0 );
|
|
||||||
sgdNormalizeVec3( normal );
|
|
||||||
|
|
||||||
normals.push_back(Point3D(normal[0], normal[1], normal[2]));
|
normals.push_back(normalize(normal));
|
||||||
ptr += 3;
|
ptr += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,7 +545,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
sgEndianSwap( (uint32_t *)&(fptr[0]) );
|
||||||
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
sgEndianSwap( (uint32_t *)&(fptr[1]) );
|
||||||
}
|
}
|
||||||
texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) );
|
texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) );
|
||||||
fptr += 2;
|
fptr += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -612,10 +610,6 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
bool SGBinObject::write_bin( const string& base, const string& name,
|
bool SGBinObject::write_bin( const string& base, const string& name,
|
||||||
const SGBucket& b )
|
const SGBucket& b )
|
||||||
{
|
{
|
||||||
Point3D p;
|
|
||||||
sgVec2 t;
|
|
||||||
sgVec3 pt;
|
|
||||||
sgVec4 color;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
unsigned char idx_mask;
|
unsigned char idx_mask;
|
||||||
int idx_size;
|
int idx_size;
|
||||||
@@ -738,9 +732,8 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
|||||||
sgWriteShort( fp, 1 ); // nelements
|
sgWriteShort( fp, 1 ); // nelements
|
||||||
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
|
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
|
||||||
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
||||||
p = wgs84_nodes[i] - gbs_center;
|
SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center);
|
||||||
sgSetVec3( pt, p.x(), p.y(), p.z() );
|
sgWriteVec3( fp, p.data() );
|
||||||
sgWriteVec3( fp, pt );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump vertex color list
|
// dump vertex color list
|
||||||
@@ -749,12 +742,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
|||||||
sgWriteShort( fp, 1 ); // nelements
|
sgWriteShort( fp, 1 ); // nelements
|
||||||
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
|
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
|
||||||
for ( i = 0; i < (int)colors.size(); ++i ) {
|
for ( i = 0; i < (int)colors.size(); ++i ) {
|
||||||
p = colors[i];
|
sgWriteVec4( fp, colors[i].data() );
|
||||||
// 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump vertex normal list
|
// dump vertex normal list
|
||||||
@@ -764,7 +752,7 @@ bool SGBinObject::write_bin( const string& base, const string& name,
|
|||||||
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
|
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
|
||||||
char normal[3];
|
char normal[3];
|
||||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
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[0] = (unsigned char)((p.x() + 1.0) * 127.5);
|
||||||
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
|
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
|
||||||
normal[2] = (unsigned char)((p.z() + 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
|
sgWriteShort( fp, 1 ); // nelements
|
||||||
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
|
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
|
||||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
||||||
p = texcoords[i];
|
sgWriteVec2( fp, texcoords[i].data() );
|
||||||
sgSetVec2( t, p.x(), p.y() );
|
|
||||||
sgWriteVec2( fp, t );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump point groups if they exist
|
// 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,
|
bool SGBinObject::write_ascii( const string& base, const string& name,
|
||||||
const SGBucket& b )
|
const SGBucket& b )
|
||||||
{
|
{
|
||||||
Point3D p;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
SGPath file = base + "/" + b.gen_base_path() + "/" + name;
|
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
|
// dump vertex list
|
||||||
fprintf(fp, "# vertex list\n");
|
fprintf(fp, "# vertex list\n");
|
||||||
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
|
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() );
|
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");
|
fprintf(fp, "# vertex normal list\n");
|
||||||
for ( i = 0; i < (int)normals.size(); ++i ) {
|
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, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() );
|
||||||
}
|
}
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
@@ -1100,7 +1085,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
|||||||
// dump texture coordinates
|
// dump texture coordinates
|
||||||
fprintf(fp, "# texture coordinate list\n");
|
fprintf(fp, "# texture coordinate list\n");
|
||||||
for ( i = 0; i < (int)texcoords.size(); ++i ) {
|
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, "vt %.5f %.5f\n", p.x(), p.y() );
|
||||||
}
|
}
|
||||||
fprintf(fp, "\n");
|
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
|
// make a list of points for the group
|
||||||
point_list group_nodes;
|
point_list group_nodes;
|
||||||
group_nodes.clear();
|
group_nodes.clear();
|
||||||
Point3D bs_center;
|
SGVec3d bs_center;
|
||||||
double bs_radius = 0;
|
double bs_radius = 0;
|
||||||
for ( i = start; i < end; ++i ) {
|
for ( i = start; i < end; ++i ) {
|
||||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||||
group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] );
|
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ tris_v[i][j] ]) );
|
||||||
bs_center = sgCalcCenter( group_nodes );
|
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
|
||||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
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
|
// make a list of points for the group
|
||||||
point_list group_nodes;
|
point_list group_nodes;
|
||||||
group_nodes.clear();
|
group_nodes.clear();
|
||||||
Point3D bs_center;
|
SGVec3d bs_center;
|
||||||
double bs_radius = 0;
|
double bs_radius = 0;
|
||||||
for ( i = start; i < end; ++i ) {
|
for ( i = start; i < end; ++i ) {
|
||||||
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
||||||
group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] );
|
group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ strips_v[i][j] ]) );
|
||||||
bs_center = sgCalcCenter( group_nodes );
|
bs_center = sgCalcCenter( group_nodes ).toSGVec3d();
|
||||||
bs_radius = sgCalcBoundingRadius( bs_center, group_nodes );
|
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 {
|
class SGBinObject {
|
||||||
unsigned short version;
|
unsigned short version;
|
||||||
|
|
||||||
Point3D gbs_center;
|
SGVec3d gbs_center;
|
||||||
float gbs_radius;
|
float gbs_radius;
|
||||||
|
|
||||||
point_list wgs84_nodes; // vertex list
|
std::vector<SGVec3d> wgs84_nodes; // vertex list
|
||||||
point_list colors; // color list
|
std::vector<SGVec4f> colors; // color list
|
||||||
point_list normals; // normal list
|
std::vector<SGVec3f> normals; // normal list
|
||||||
point_list texcoords; // texture coordinate list
|
std::vector<SGVec2f> texcoords; // texture coordinate list
|
||||||
|
|
||||||
group_list pts_v; // points vertex index
|
group_list pts_v; // points vertex index
|
||||||
group_list pts_n; // points normal index
|
group_list pts_n; // points normal index
|
||||||
@@ -125,23 +125,51 @@ public:
|
|||||||
|
|
||||||
inline unsigned short get_version() const { return version; }
|
inline unsigned short get_version() const { return version; }
|
||||||
|
|
||||||
inline const Point3D& get_gbs_center() const { return gbs_center; }
|
inline Point3D get_gbs_center() const { return Point3D::fromSGVec3(gbs_center); }
|
||||||
inline void set_gbs_center( const Point3D& p ) { gbs_center = p; }
|
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 float get_gbs_radius() const { return gbs_radius; }
|
||||||
inline void set_gbs_radius( float r ) { gbs_radius = r; }
|
inline void set_gbs_radius( float r ) { gbs_radius = r; }
|
||||||
|
|
||||||
inline const point_list& get_wgs84_nodes() const { return wgs84_nodes; }
|
inline const std::vector<SGVec3d>& get_wgs84_nodes() const
|
||||||
inline void set_wgs84_nodes( const point_list& n ) { wgs84_nodes = n; }
|
{ 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 const std::vector<SGVec4f>& get_colors() const { return colors; }
|
||||||
inline void set_colors( const point_list& c ) { colors = c; }
|
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 const std::vector<SGVec3f>& get_normals() const { return normals; }
|
||||||
inline void set_normals( const point_list& n ) { normals = n; }
|
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 const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
|
||||||
inline void set_texcoords( const point_list& t ) { texcoords = t; }
|
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 const group_list& get_pts_v() const { return pts_v; }
|
||||||
inline void set_pts_v( const group_list& g ) { pts_v = g; }
|
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 <simgear/compiler.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|||||||
+73
-61
@@ -23,6 +23,19 @@
|
|||||||
//
|
//
|
||||||
// Put in some bullet-proofing to handle magnetic and geographic poles.
|
// Put in some bullet-proofing to handle magnetic and geographic poles.
|
||||||
// 3/28/2000 EAW
|
// 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
|
// The routine uses a spherical harmonic expansion of the magnetic
|
||||||
// potential up to twelfth order, together with its time variation, as
|
// potential up to twelfth order, together with its time variation, as
|
||||||
@@ -75,74 +88,72 @@
|
|||||||
|
|
||||||
|
|
||||||
static const double pi = 3.14159265358979;
|
static const double pi = 3.14159265358979;
|
||||||
static const double a = 6378.16; /* major radius (km) IAU66 ellipsoid */
|
static const double a = 6378.137; /* semi-major axis (equatorial radius) of WGS84 ellipsoid */
|
||||||
static const double f = 1.0 / 298.25; /* inverse flattening IAU66 ellipsoid */
|
static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
|
||||||
static const double b = 6378.16 * (1.0 -1.0 / 298.25 );
|
static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
|
||||||
/* minor radius b=a*(1-f) */
|
|
||||||
static const double r_0 = 6371.2; /* "mean radius" for spherical harmonic expansion */
|
|
||||||
|
|
||||||
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},
|
{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},
|
{-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},
|
||||||
{-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},
|
{-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},
|
||||||
{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},
|
{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},
|
||||||
{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},
|
{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},
|
||||||
{-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},
|
{-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.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},
|
{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},
|
||||||
{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},
|
{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},
|
||||||
{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},
|
{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.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},
|
{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.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},
|
{-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},
|
||||||
{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},
|
{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},
|
||||||
{-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},
|
{-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, 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, 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, -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, -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, -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, -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, 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, 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.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, 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, -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, -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, -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, -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, 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, 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.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, -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, 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, 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, -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, 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, -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, -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},
|
{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},
|
{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},
|
||||||
{-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},
|
{-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.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},
|
{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},
|
||||||
{-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},
|
{-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},
|
||||||
{-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},
|
{-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},
|
||||||
{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.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.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.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.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},
|
{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},
|
||||||
{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, 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, -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, -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, -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, 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, 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.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, 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, 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.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.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, -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, 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.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.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, -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},
|
{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 */
|
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||||
int n,m;
|
int n,m;
|
||||||
/* reference dates */
|
/* reference date for current model is 1 januari 2005 */
|
||||||
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,fn_0,B_r,B_theta,B_phi,X,Y,Z;
|
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;
|
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 */
|
/* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
|
||||||
/* WMM2000 */
|
achieved by adjusting the coefficients at time t0 for linear secular variation */
|
||||||
yearfrac = (dat - date0_wmm2000) / 365.25;
|
/* WMM2005 */
|
||||||
|
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||||
for ( n = 1; n <= nmax; n++ ) {
|
for ( n = 1; n <= nmax; n++ ) {
|
||||||
for ( m = 0; m <= nmax; m++ ) {
|
for ( m = 0; m <= nmax; m++ ) {
|
||||||
gnm[n][m] = gnm_wmm2000[n][m] + yearfrac * gtnm_wmm2000[n][m];
|
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||||
hnm[n][m] = hnm_wmm2000[n][m] + yearfrac * htnm_wmm2000[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 */
|
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||||
int n,m;
|
int n,m;
|
||||||
/* reference dates */
|
/* 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;
|
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 */
|
/* compute gnm, hnm at dat */
|
||||||
/* WMM2000 */
|
/* WMM2005 */
|
||||||
yearfrac = (dat - date0_wmm2000) / 365.25;
|
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||||
for ( n = 1; n <= nmax; n++ ) {
|
for ( n = 1; n <= nmax; n++ ) {
|
||||||
for ( m = 0; m <= nmax; m++ ) {
|
for ( m = 0; m <= nmax; m++ ) {
|
||||||
gnm[n][m] = gnm_wmm2000[n][m] + yearfrac * gtnm_wmm2000[n][m];
|
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||||
hnm[n][m] = hnm_wmm2000[n][m] + yearfrac * htnm_wmm2000[n][m];
|
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
includedir = @includedir@/math
|
includedir = @includedir@/math
|
||||||
|
|
||||||
noinst_PROGRAMS = SGMathTest
|
check_PROGRAMS = SGMathTest SGGeometryTest
|
||||||
check_PROGRAMS = SGMathTest
|
|
||||||
TESTS = $(check_PROGRAMS)
|
TESTS = $(check_PROGRAMS)
|
||||||
|
|
||||||
SGMathTest_SOURCES = SGMathTest.cxx
|
SGMathTest_SOURCES = SGMathTest.cxx
|
||||||
SGMathTest_LDADD = libsgmath.a $(base_LIBS)
|
SGMathTest_LDADD = libsgmath.a $(base_LIBS)
|
||||||
|
|
||||||
|
SGGeometryTest_SOURCES = SGGeometryTest.cxx
|
||||||
|
SGGeometryTest_LDADD = libsgmath.a $(base_LIBS)
|
||||||
|
|
||||||
lib_LIBRARIES = libsgmath.a
|
lib_LIBRARIES = libsgmath.a
|
||||||
|
|
||||||
@@ -20,20 +21,28 @@ include_HEADERS = \
|
|||||||
sg_random.h \
|
sg_random.h \
|
||||||
sg_types.hxx \
|
sg_types.hxx \
|
||||||
vector.hxx \
|
vector.hxx \
|
||||||
fastmath.hxx \
|
SGBox.hxx \
|
||||||
|
SGCMath.hxx \
|
||||||
SGGeoc.hxx \
|
SGGeoc.hxx \
|
||||||
SGGeod.hxx \
|
SGGeod.hxx \
|
||||||
SGGeodesy.hxx \
|
SGGeodesy.hxx \
|
||||||
|
SGGeometry.hxx \
|
||||||
|
SGGeometryFwd.hxx \
|
||||||
|
SGIntersect.hxx \
|
||||||
SGLimits.hxx \
|
SGLimits.hxx \
|
||||||
|
SGLineSegment.hxx \
|
||||||
SGMatrix.hxx \
|
SGMatrix.hxx \
|
||||||
SGMath.hxx \
|
SGMath.hxx \
|
||||||
|
SGMathFwd.hxx \
|
||||||
SGMisc.hxx \
|
SGMisc.hxx \
|
||||||
|
SGPlane.hxx \
|
||||||
SGQuat.hxx \
|
SGQuat.hxx \
|
||||||
SGVec4.hxx \
|
SGRay.hxx \
|
||||||
SGVec3.hxx
|
SGSphere.hxx \
|
||||||
|
SGTriangle.hxx \
|
||||||
|
SGVec2.hxx \
|
||||||
EXTRA_DIST = linintp2.h linintp2.inl sphrintp.h sphrintp.inl
|
SGVec3.hxx \
|
||||||
|
SGVec4.hxx
|
||||||
|
|
||||||
libsgmath_a_SOURCES = \
|
libsgmath_a_SOURCES = \
|
||||||
interpolater.cxx \
|
interpolater.cxx \
|
||||||
@@ -42,7 +51,6 @@ libsgmath_a_SOURCES = \
|
|||||||
sg_geodesy.cxx \
|
sg_geodesy.cxx \
|
||||||
sg_random.c \
|
sg_random.c \
|
||||||
vector.cxx \
|
vector.cxx \
|
||||||
fastmath.cxx \
|
|
||||||
SGGeodesy.cxx
|
SGGeodesy.cxx
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)
|
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:
|
public:
|
||||||
/// Default constructor, initializes the instance to lat = lon = lat = 0
|
/// Default constructor, initializes the instance to lat = lon = lat = 0
|
||||||
SGGeoc(void);
|
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
|
/// Factory from angular values in radians and radius in ft
|
||||||
static SGGeoc fromRadFt(double lon, double lat, double radius);
|
static SGGeoc fromRadFt(double lon, double lat, double radius);
|
||||||
@@ -42,6 +36,13 @@ public:
|
|||||||
static SGGeoc fromRadM(double lon, double lat, double radius);
|
static SGGeoc fromRadM(double lon, double lat, double radius);
|
||||||
/// Factory from angular values in degrees and radius in m
|
/// Factory from angular values in degrees and radius in m
|
||||||
static SGGeoc fromDegM(double lon, double lat, double radius);
|
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
|
/// Return the geocentric longitude in radians
|
||||||
double getLongitudeRad(void) const;
|
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
|
inline
|
||||||
SGGeoc
|
SGGeoc
|
||||||
SGGeoc::fromRadFt(double lon, double lat, double radius)
|
SGGeoc::fromRadFt(double lon, double lat, double radius)
|
||||||
@@ -165,6 +152,26 @@ SGGeoc::fromDegM(double lon, double lat, double radius)
|
|||||||
#endif
|
#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
|
inline
|
||||||
double
|
double
|
||||||
SGGeoc::getLongitudeRad(void) const
|
SGGeoc::getLongitudeRad(void) const
|
||||||
|
|||||||
+27
-20
@@ -27,12 +27,6 @@ class SGGeod {
|
|||||||
public:
|
public:
|
||||||
/// Default constructor, initializes the instance to lat = lon = elev = 0
|
/// Default constructor, initializes the instance to lat = lon = elev = 0
|
||||||
SGGeod(void);
|
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
|
/// Factory from angular values in radians and elevation is 0
|
||||||
static SGGeod fromRad(double lon, double lat);
|
static SGGeod fromRad(double lon, double lat);
|
||||||
@@ -46,6 +40,13 @@ public:
|
|||||||
static SGGeod fromRadM(double lon, double lat, double elevation);
|
static SGGeod fromRadM(double lon, double lat, double elevation);
|
||||||
/// Factory from angular values in degrees and elevation in m
|
/// Factory from angular values in degrees and elevation in m
|
||||||
static SGGeod fromDegM(double lon, double lat, double elevation);
|
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
|
/// Return the geodetic longitude in radians
|
||||||
double getLongitudeRad(void) const;
|
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
|
inline
|
||||||
SGGeod
|
SGGeod
|
||||||
SGGeod::fromRad(double lon, double lat)
|
SGGeod::fromRad(double lon, double lat)
|
||||||
@@ -191,6 +178,26 @@ SGGeod::fromDegM(double lon, double lat, double elevation)
|
|||||||
#endif
|
#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
|
inline
|
||||||
double
|
double
|
||||||
SGGeod::getLongitudeRad(void) const
|
SGGeod::getLongitudeRad(void) const
|
||||||
|
|||||||
@@ -18,12 +18,6 @@
|
|||||||
#ifndef SGGeodesy_H
|
#ifndef SGGeodesy_H
|
||||||
#define SGGeodesy_H
|
#define SGGeodesy_H
|
||||||
|
|
||||||
class SGGeoc;
|
|
||||||
class SGGeod;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class SGVec3;
|
|
||||||
|
|
||||||
class SGGeodesy {
|
class SGGeodesy {
|
||||||
public:
|
public:
|
||||||
// Hard numbers from the WGS84 standard.
|
// 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>
|
template<typename T>
|
||||||
class SGLimits : public std::numeric_limits<T> {};
|
class SGLimits : public std::numeric_limits<T> {};
|
||||||
|
|
||||||
typedef SGLimits<float> SGLimitsf;
|
|
||||||
typedef SGLimits<double> SGLimitsd;
|
|
||||||
|
|
||||||
#endif
|
#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
|
/// Just include them all
|
||||||
|
|
||||||
#include <iosfwd>
|
#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 "SGLimits.hxx"
|
||||||
#include "SGMisc.hxx"
|
#include "SGMisc.hxx"
|
||||||
#include "SGGeodesy.hxx"
|
#include "SGGeodesy.hxx"
|
||||||
|
#include "SGVec2.hxx"
|
||||||
#include "SGVec3.hxx"
|
#include "SGVec3.hxx"
|
||||||
#include "SGVec4.hxx"
|
#include "SGVec4.hxx"
|
||||||
#include "SGQuat.hxx"
|
|
||||||
#include "SGMatrix.hxx"
|
|
||||||
#include "SGGeoc.hxx"
|
#include "SGGeoc.hxx"
|
||||||
#include "SGGeod.hxx"
|
#include "SGGeod.hxx"
|
||||||
|
#include "SGQuat.hxx"
|
||||||
|
#include "SGMatrix.hxx"
|
||||||
|
|
||||||
#endif
|
#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
|
// Create some test matrix
|
||||||
SGVec3<T> v0(2, 7, 17);
|
SGVec3<T> v0(2, 7, 17);
|
||||||
SGQuat<T> q0 = SGQuat<T>::fromAngleAxis(SGMisc<T>::pi(), normalize(v0));
|
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
|
// Check the tqo forms of the inverse for that kind of special matrix
|
||||||
SGMatrix<T> m1, m2;
|
SGMatrix<T> m1, m2;
|
||||||
@@ -213,16 +215,16 @@ GeodesyTest(void)
|
|||||||
geod0 = SGGeod::fromDegM(30, 20, 17);
|
geod0 = SGGeod::fromDegM(30, 20, 17);
|
||||||
|
|
||||||
// Test the conversion routines to cartesian coordinates
|
// Test the conversion routines to cartesian coordinates
|
||||||
cart0 = geod0;
|
cart0 = SGVec3<double>::fromGeod(geod0);
|
||||||
geod1 = cart0;
|
geod1 = SGGeod::fromCart(cart0);
|
||||||
if (epsDeg < fabs(geod0.getLongitudeDeg() - geod1.getLongitudeDeg()) ||
|
if (epsDeg < fabs(geod0.getLongitudeDeg() - geod1.getLongitudeDeg()) ||
|
||||||
epsDeg < fabs(geod0.getLatitudeDeg() - geod1.getLatitudeDeg()) ||
|
epsDeg < fabs(geod0.getLatitudeDeg() - geod1.getLatitudeDeg()) ||
|
||||||
epsM < fabs(geod0.getElevationM() - geod1.getElevationM()))
|
epsM < fabs(geod0.getElevationM() - geod1.getElevationM()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Test the conversion routines to radial coordinates
|
// Test the conversion routines to radial coordinates
|
||||||
geoc0 = cart0;
|
geoc0 = SGGeoc::fromCart(cart0);
|
||||||
cart1 = geoc0;
|
cart1 = SGVec3<double>::fromGeoc(geoc0);
|
||||||
if (!equivalent(cart0, cart1))
|
if (!equivalent(cart0, cart1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -236,7 +238,9 @@ sgInterfaceTest(void)
|
|||||||
SGVec3f v3f = SGVec3f::e2();
|
SGVec3f v3f = SGVec3f::e2();
|
||||||
SGVec4f v4f = SGVec4f::e2();
|
SGVec4f v4f = SGVec4f::e2();
|
||||||
SGQuatf qf = SGQuatf::fromEulerRad(1.2, 1.3, -0.4);
|
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,
|
// Copy to and from plibs types check if result is equal,
|
||||||
// test for exact equality
|
// test for exact equality
|
||||||
@@ -283,7 +287,9 @@ sgdInterfaceTest(void)
|
|||||||
SGVec3d v3d = SGVec3d::e2();
|
SGVec3d v3d = SGVec3d::e2();
|
||||||
SGVec4d v4d = SGVec4d::e2();
|
SGVec4d v4d = SGVec4d::e2();
|
||||||
SGQuatd qd = SGQuatd::fromEulerRad(1.2, 1.3, -0.4);
|
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,
|
// Copy to and from plibs types check if result is equal,
|
||||||
// test for exact equality
|
// test for exact equality
|
||||||
@@ -346,8 +352,8 @@ main(void)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
// Check geodetic/geocentric/cartesian conversions
|
// Check geodetic/geocentric/cartesian conversions
|
||||||
// if (!GeodesyTest())
|
if (!GeodesyTest())
|
||||||
// return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
// Check interaction with sg*/sgd*
|
// Check interaction with sg*/sgd*
|
||||||
if (!sgInterfaceTest())
|
if (!sgInterfaceTest())
|
||||||
|
|||||||
+54
-40
@@ -22,9 +22,6 @@
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct TransNegRef;
|
struct TransNegRef;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class SGMatrix;
|
|
||||||
|
|
||||||
/// 3D Matrix Class
|
/// 3D Matrix Class
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGMatrix {
|
class SGMatrix {
|
||||||
@@ -66,14 +63,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Constructor, build up a SGMatrix from a translation
|
/// Constructor, build up a SGMatrix from a translation
|
||||||
SGMatrix(const SGVec3<T>& trans)
|
template<typename S>
|
||||||
|
SGMatrix(const SGVec3<S>& trans)
|
||||||
{ set(trans); }
|
{ set(trans); }
|
||||||
|
|
||||||
/// Constructor, build up a SGMatrix from a rotation and a translation
|
/// Constructor, build up a SGMatrix from a rotation and a translation
|
||||||
SGMatrix(const SGQuat<T>& quat, const SGVec3<T>& trans)
|
template<typename S>
|
||||||
{ set(quat, trans); }
|
SGMatrix(const SGQuat<S>& quat)
|
||||||
/// Constructor, build up a SGMatrix from a rotation and a translation
|
|
||||||
SGMatrix(const SGQuat<T>& quat)
|
|
||||||
{ set(quat); }
|
{ set(quat); }
|
||||||
|
|
||||||
/// Copy constructor for a transposed negated matrix
|
/// Copy constructor for a transposed negated matrix
|
||||||
@@ -81,39 +77,22 @@ public:
|
|||||||
{ set(tm); }
|
{ set(tm); }
|
||||||
|
|
||||||
/// Set from a tranlation
|
/// 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[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[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[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[3] = 0; _data.flat[7] = 0;
|
||||||
_data.flat[11] = 0; _data.flat[15] = 1;
|
_data.flat[11] = 0; _data.flat[15] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set from a scale/rotation and tranlation
|
/// Set from a scale/rotation and tranlation
|
||||||
void set(const SGQuat<T>& quat, const SGVec3<T>& trans)
|
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;
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
T w = quat.w(); T x = quat.x(); T y = quat.y(); T z = quat.z();
|
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 xx = x*x; T yy = y*y; T zz = z*z;
|
||||||
@@ -202,6 +181,45 @@ public:
|
|||||||
/// Inplace matrix multiplication, post multiply
|
/// Inplace matrix multiplication, post multiply
|
||||||
SGMatrix& operator*=(const SGMatrix<T>& m2);
|
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> xformPt(const SGVec3<T>& pt) const
|
||||||
{
|
{
|
||||||
SGVec3<T> tpt;
|
SGVec3<T> tpt;
|
||||||
@@ -571,18 +589,14 @@ operator<<(std::basic_ostream<char_type, traits_type>& s, const SGMatrix<T>& m)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Two classes doing actually the same on different types
|
|
||||||
typedef SGMatrix<float> SGMatrixf;
|
|
||||||
typedef SGMatrix<double> SGMatrixd;
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
SGMatrixf
|
SGMatrixf
|
||||||
toMatrixf(const SGMatrixd& m)
|
toMatrixf(const SGMatrixd& m)
|
||||||
{
|
{
|
||||||
return SGMatrixf((float)m(0,0), (float)m(0,1), (float)m(0,2), (float)m(0,3),
|
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(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(2,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(3,0), (float)m(3,1), (float)m(3,2), (float)m(3,3));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -591,8 +605,8 @@ toMatrixd(const SGMatrixf& m)
|
|||||||
{
|
{
|
||||||
return SGMatrixd(m(0,0), m(0,1), m(0,2), m(0,3),
|
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(1,0), m(1,1), m(1,2), m(1,3),
|
||||||
m(3,0), m(2,1), m(2,2), m(2,3),
|
m(2,0), m(2,1), m(2,2), m(2,3),
|
||||||
m(4,0), m(4,1), m(4,2), m(4,3));
|
m(3,0), m(3,1), m(3,2), m(3,3));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+38
-5
@@ -18,12 +18,12 @@
|
|||||||
#ifndef SGMisc_H
|
#ifndef SGMisc_H
|
||||||
#define SGMisc_H
|
#define SGMisc_H
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGMisc {
|
class SGMisc {
|
||||||
public:
|
public:
|
||||||
static T pi() { return T(3.1415926535897932384626433832795029L); }
|
static T pi() { return T(3.1415926535897932384626433832795029L); }
|
||||||
|
static T twopi() { return 2*T(3.1415926535897932384626433832795029L); }
|
||||||
|
|
||||||
static T min(const T& a, const T& b)
|
static T min(const T& a, const T& b)
|
||||||
{ return a < b ? a : b; }
|
{ return a < b ? a : b; }
|
||||||
static T min(const T& a, const T& b, const T& c)
|
static T min(const T& a, const T& b, const T& c)
|
||||||
@@ -36,6 +36,11 @@ public:
|
|||||||
{ return max(max(a, b), c); }
|
{ return max(max(a, b), c); }
|
||||||
static T max(const T& a, const T& b, const T& c, const T& d)
|
static T max(const T& a, const T& b, const T& c, const T& d)
|
||||||
{ return max(max(max(a, b), c), 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)
|
static int sign(const T& a)
|
||||||
{
|
{
|
||||||
if (a < -SGLimits<T>::min())
|
if (a < -SGLimits<T>::min())
|
||||||
@@ -51,6 +56,37 @@ public:
|
|||||||
static T deg2rad(const T& val)
|
static T deg2rad(const T& val)
|
||||||
{ return val*pi()/180; }
|
{ 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
|
#ifndef NDEBUG
|
||||||
/// Returns true if v is a NaN value
|
/// Returns true if v is a NaN value
|
||||||
/// Use with care: allways code that you do not need to use that!
|
/// Use with care: allways code that you do not need to use that!
|
||||||
@@ -71,7 +107,4 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SGMisc<float> SGMiscf;
|
|
||||||
typedef SGMisc<double> SGMiscd;
|
|
||||||
|
|
||||||
#endif
|
#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
|
#ifndef SGQuat_H
|
||||||
#define 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
|
/// 3D Vector Class
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGQuat {
|
class SGQuat : protected SGQuatStorage<T> {
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
|
|
||||||
@@ -33,7 +74,7 @@ public:
|
|||||||
/// uninitialized values in the debug build very fast ...
|
/// uninitialized values in the debug build very fast ...
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
for (unsigned i = 0; i < 4; ++i)
|
for (unsigned i = 0; i < 4; ++i)
|
||||||
_data[i] = SGLimits<T>::quiet_NaN();
|
data()[i] = SGLimits<T>::quiet_NaN();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/// Constructor. Initialize by the given values
|
/// Constructor. Initialize by the given values
|
||||||
@@ -42,11 +83,13 @@ public:
|
|||||||
/// Constructor. Initialize by the content of a plain array,
|
/// Constructor. Initialize by the content of a plain array,
|
||||||
/// make sure it has at least 4 elements
|
/// make sure it has at least 4 elements
|
||||||
explicit SGQuat(const T* d)
|
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
|
/// Return a unit quaternion
|
||||||
static SGQuat unit(void)
|
static SGQuat unit(void)
|
||||||
{ return fromRealImag(1, SGVec3<T>(0)); }
|
{ return fromRealImag(1, SGVec3<T>(0, 0, 0)); }
|
||||||
|
|
||||||
/// Return a quaternion from euler angles
|
/// Return a quaternion from euler angles
|
||||||
static SGQuat fromEulerRad(T z, T y, T x)
|
static SGQuat fromEulerRad(T z, T y, T x)
|
||||||
@@ -87,13 +130,17 @@ public:
|
|||||||
static SGQuat fromHeadAttBankDeg(T h, T a, T b)
|
static SGQuat fromHeadAttBankDeg(T h, T a, T b)
|
||||||
{ return fromEulerDeg(h, a, b); }
|
{ return fromEulerDeg(h, a, b); }
|
||||||
|
|
||||||
/// Return a quaternion rotation the the horizontal local frame from given
|
/// Return a quaternion rotation from the earth centered to the
|
||||||
/// longitude and latitude
|
/// 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)
|
static SGQuat fromLonLatRad(T lon, T lat)
|
||||||
{
|
{
|
||||||
SGQuat q;
|
SGQuat q;
|
||||||
T zd2 = T(0.5)*lon;
|
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 Szd2 = sin(zd2);
|
||||||
T Syd2 = sin(yd2);
|
T Syd2 = sin(yd2);
|
||||||
T Czd2 = cos(zd2);
|
T Czd2 = cos(zd2);
|
||||||
@@ -104,11 +151,50 @@ public:
|
|||||||
q.z() = Szd2*Cyd2;
|
q.z() = Szd2*Cyd2;
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
/// Like the above provided for convenience
|
||||||
/// Return a quaternion rotation the the horizontal local frame from given
|
|
||||||
/// longitude and latitude
|
|
||||||
static SGQuat fromLonLatDeg(T lon, T lat)
|
static SGQuat fromLonLatDeg(T lon, T lat)
|
||||||
{ return fromLonLatRad(SGMisc<T>::deg2rad(lon), SGMisc<T>::deg2rad(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
|
/// Create a quaternion from the angle axis representation
|
||||||
static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
|
static SGQuat fromAngleAxis(T angle, const SGVec3<T>& axis)
|
||||||
@@ -132,14 +218,100 @@ public:
|
|||||||
return fromRealImag(cos(angle2), T(sin(angle2)/nAxis)*axis);
|
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
|
/// Return a quaternion from real and imaginary part
|
||||||
static SGQuat fromRealImag(T r, const SGVec3<T>& i)
|
static SGQuat fromRealImag(T r, const SGVec3<T>& i)
|
||||||
{
|
{
|
||||||
SGQuat q;
|
SGQuat q;
|
||||||
q.w() = r;
|
q.w() = r;
|
||||||
q.x() = i(0);
|
q.x() = i.x();
|
||||||
q.y() = i(1);
|
q.y() = i.y();
|
||||||
q.z() = i(2);
|
q.z() = i.z();
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,36 +322,36 @@ public:
|
|||||||
/// write the euler angles into the references
|
/// write the euler angles into the references
|
||||||
void getEulerRad(T& zRad, T& yRad, T& xRad) const
|
void getEulerRad(T& zRad, T& yRad, T& xRad) const
|
||||||
{
|
{
|
||||||
value_type sqrQW = w()*w();
|
T sqrQW = w()*w();
|
||||||
value_type sqrQX = x()*x();
|
T sqrQX = x()*x();
|
||||||
value_type sqrQY = y()*y();
|
T sqrQY = y()*y();
|
||||||
value_type sqrQZ = z()*z();
|
T sqrQZ = z()*z();
|
||||||
|
|
||||||
value_type num = 2*(y()*z() + w()*x());
|
T num = 2*(y()*z() + w()*x());
|
||||||
value_type den = sqrQW - sqrQX - sqrQY + sqrQZ;
|
T den = sqrQW - sqrQX - sqrQY + sqrQZ;
|
||||||
if (fabs(den) < SGLimits<value_type>::min() &&
|
if (fabs(den) < SGLimits<T>::min() &&
|
||||||
fabs(num) < SGLimits<value_type>::min())
|
fabs(num) < SGLimits<T>::min())
|
||||||
xRad = 0;
|
xRad = 0;
|
||||||
else
|
else
|
||||||
xRad = atan2(num, den);
|
xRad = atan2(num, den);
|
||||||
|
|
||||||
value_type tmp = 2*(x()*z() - w()*y());
|
T tmp = 2*(x()*z() - w()*y());
|
||||||
if (tmp < -1)
|
if (tmp < -1)
|
||||||
yRad = 0.5*SGMisc<value_type>::pi();
|
yRad = 0.5*SGMisc<T>::pi();
|
||||||
else if (1 < tmp)
|
else if (1 < tmp)
|
||||||
yRad = -0.5*SGMisc<value_type>::pi();
|
yRad = -0.5*SGMisc<T>::pi();
|
||||||
else
|
else
|
||||||
yRad = -asin(tmp);
|
yRad = -asin(tmp);
|
||||||
|
|
||||||
num = 2*(x()*y() + w()*z());
|
num = 2*(x()*y() + w()*z());
|
||||||
den = sqrQW + sqrQX - sqrQY - sqrQZ;
|
den = sqrQW + sqrQX - sqrQY - sqrQZ;
|
||||||
if (fabs(den) < SGLimits<value_type>::min() &&
|
if (fabs(den) < SGLimits<T>::min() &&
|
||||||
fabs(num) < SGLimits<value_type>::min())
|
fabs(num) < SGLimits<T>::min())
|
||||||
zRad = 0;
|
zRad = 0;
|
||||||
else {
|
else {
|
||||||
value_type psi = atan2(num, den);
|
T psi = atan2(num, den);
|
||||||
if (psi < 0)
|
if (psi < 0)
|
||||||
psi += 2*SGMisc<value_type>::pi();
|
psi += 2*SGMisc<T>::pi();
|
||||||
zRad = psi;
|
zRad = psi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,67 +394,66 @@ public:
|
|||||||
|
|
||||||
/// Access by index, the index is unchecked
|
/// Access by index, the index is unchecked
|
||||||
const T& operator()(unsigned i) const
|
const T& operator()(unsigned i) const
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
/// Access by index, the index is unchecked
|
/// Access by index, the index is unchecked
|
||||||
T& operator()(unsigned i)
|
T& operator()(unsigned i)
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
|
|
||||||
/// Access raw data by index, the index is unchecked
|
/// Access raw data by index, the index is unchecked
|
||||||
const T& operator[](unsigned i) const
|
const T& operator[](unsigned i) const
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
/// Access raw data by index, the index is unchecked
|
/// Access raw data by index, the index is unchecked
|
||||||
T& operator[](unsigned i)
|
T& operator[](unsigned i)
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
|
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
const T& x(void) const
|
const T& x(void) const
|
||||||
{ return _data[0]; }
|
{ return data()[0]; }
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
T& x(void)
|
T& x(void)
|
||||||
{ return _data[0]; }
|
{ return data()[0]; }
|
||||||
/// Access the y component
|
/// Access the y component
|
||||||
const T& y(void) const
|
const T& y(void) const
|
||||||
{ return _data[1]; }
|
{ return data()[1]; }
|
||||||
/// Access the y component
|
/// Access the y component
|
||||||
T& y(void)
|
T& y(void)
|
||||||
{ return _data[1]; }
|
{ return data()[1]; }
|
||||||
/// Access the z component
|
/// Access the z component
|
||||||
const T& z(void) const
|
const T& z(void) const
|
||||||
{ return _data[2]; }
|
{ return data()[2]; }
|
||||||
/// Access the z component
|
/// Access the z component
|
||||||
T& z(void)
|
T& z(void)
|
||||||
{ return _data[2]; }
|
{ return data()[2]; }
|
||||||
/// Access the w component
|
/// Access the w component
|
||||||
const T& w(void) const
|
const T& w(void) const
|
||||||
{ return _data[3]; }
|
{ return data()[3]; }
|
||||||
/// Access the w component
|
/// Access the w component
|
||||||
T& w(void)
|
T& w(void)
|
||||||
{ return _data[3]; }
|
{ return data()[3]; }
|
||||||
|
|
||||||
/// Get the data pointer, usefull for interfacing with plib's sg*Vec
|
/// Get the data pointer
|
||||||
const T* data(void) const
|
using SGQuatStorage<T>::data;
|
||||||
{ 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 sgQuat/sgdQuat
|
/// Readonly interface function to ssg's sgQuat/sgdQuat
|
||||||
const T (&sg(void) const)[4]
|
const T (&sg(void) const)[4]
|
||||||
{ return _data; }
|
{ return data(); }
|
||||||
/// Interface function to ssg's sgQuat/sgdQuat
|
/// Interface function to ssg's sgQuat/sgdQuat
|
||||||
T (&sg(void))[4]
|
T (&sg(void))[4]
|
||||||
{ return _data; }
|
{ return data(); }
|
||||||
|
|
||||||
|
/// Interface function to osg's Quat*
|
||||||
|
using SGQuatStorage<T>::osg;
|
||||||
|
|
||||||
/// Inplace addition
|
/// Inplace addition
|
||||||
SGQuat& operator+=(const SGQuat& v)
|
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
|
/// Inplace subtraction
|
||||||
SGQuat& operator-=(const SGQuat& v)
|
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
|
/// Inplace scalar multiplication
|
||||||
template<typename S>
|
template<typename S>
|
||||||
SGQuat& operator*=(S 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
|
/// Inplace scalar multiplication by 1/s
|
||||||
template<typename S>
|
template<typename S>
|
||||||
SGQuat& operator/=(S s)
|
SGQuat& operator/=(S s)
|
||||||
@@ -294,18 +465,18 @@ public:
|
|||||||
/// frame rotated with the quaternion
|
/// frame rotated with the quaternion
|
||||||
SGVec3<T> transform(const SGVec3<T>& v) const
|
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);
|
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);
|
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
|
/// Transform a vector from the coordinate frame rotated with the quaternion
|
||||||
/// to the current coordinate frame
|
/// to the current coordinate frame
|
||||||
SGVec3<T> backTransform(const SGVec3<T>& v) const
|
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);
|
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);
|
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
|
/// Return the time derivative of the quaternion given the angular velocity
|
||||||
SGQuat
|
SGQuat
|
||||||
derivative(const SGVec3<T>& angVel)
|
derivative(const SGVec3<T>& angVel) const
|
||||||
{
|
{
|
||||||
SGQuat deriv;
|
SGQuat deriv;
|
||||||
|
|
||||||
@@ -331,8 +502,65 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 ...
|
/// 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)
|
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGQuat<T>& v)
|
||||||
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
|
{ 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
|
inline
|
||||||
SGQuatf
|
SGQuatf
|
||||||
toQuatf(const SGQuatd& v)
|
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
|
#ifndef SGVec3_H
|
||||||
#define 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
|
/// 3D Vector Class
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGVec3 {
|
class SGVec3 : protected SGVec3Storage<T> {
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
|
|
||||||
@@ -33,82 +82,79 @@ public:
|
|||||||
/// uninitialized values in the debug build very fast ...
|
/// uninitialized values in the debug build very fast ...
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
for (unsigned i = 0; i < 3; ++i)
|
for (unsigned i = 0; i < 3; ++i)
|
||||||
_data[i] = SGLimits<T>::quiet_NaN();
|
data()[i] = SGLimits<T>::quiet_NaN();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/// Constructor. Initialize by the given values
|
/// Constructor. Initialize by the given values
|
||||||
SGVec3(T x, T y, T z)
|
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,
|
/// Constructor. Initialize by the content of a plain array,
|
||||||
/// make sure it has at least 3 elements
|
/// make sure it has at least 3 elements
|
||||||
explicit SGVec3(const T* data)
|
explicit SGVec3(const T* d)
|
||||||
{ _data[0] = data[0]; _data[1] = data[1]; _data[2] = data[2]; }
|
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||||
/// Constructor. Initialize by a geodetic coordinate
|
explicit SGVec3(const osg::Vec3f& d)
|
||||||
/// Note that this conversion is relatively expensive to compute
|
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||||
SGVec3(const SGGeod& geod)
|
explicit SGVec3(const osg::Vec3d& d)
|
||||||
{ SGGeodesy::SGGeodToCart(geod, *this); }
|
{ data()[0] = d[0]; data()[1] = d[1]; data()[2] = d[2]; }
|
||||||
/// Constructor. Initialize by a geocentric coordinate
|
explicit SGVec3(const SGVec2<T>& v2, const T& v3 = 0)
|
||||||
/// Note that this conversion is relatively expensive to compute
|
{ data()[0] = v2[0]; data()[1] = v2[1]; data()[2] = v3; }
|
||||||
SGVec3(const SGGeoc& geoc)
|
|
||||||
{ SGGeodesy::SGGeocToCart(geoc, *this); }
|
|
||||||
|
|
||||||
/// Access by index, the index is unchecked
|
/// Access by index, the index is unchecked
|
||||||
const T& operator()(unsigned i) const
|
const T& operator()(unsigned i) const
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
/// Access by index, the index is unchecked
|
/// Access by index, the index is unchecked
|
||||||
T& operator()(unsigned i)
|
T& operator()(unsigned i)
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
|
|
||||||
/// Access raw data by index, the index is unchecked
|
/// Access raw data by index, the index is unchecked
|
||||||
const T& operator[](unsigned i) const
|
const T& operator[](unsigned i) const
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
/// Access raw data by index, the index is unchecked
|
/// Access raw data by index, the index is unchecked
|
||||||
T& operator[](unsigned i)
|
T& operator[](unsigned i)
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
|
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
const T& x(void) const
|
const T& x(void) const
|
||||||
{ return _data[0]; }
|
{ return data()[0]; }
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
T& x(void)
|
T& x(void)
|
||||||
{ return _data[0]; }
|
{ return data()[0]; }
|
||||||
/// Access the y component
|
/// Access the y component
|
||||||
const T& y(void) const
|
const T& y(void) const
|
||||||
{ return _data[1]; }
|
{ return data()[1]; }
|
||||||
/// Access the y component
|
/// Access the y component
|
||||||
T& y(void)
|
T& y(void)
|
||||||
{ return _data[1]; }
|
{ return data()[1]; }
|
||||||
/// Access the z component
|
/// Access the z component
|
||||||
const T& z(void) const
|
const T& z(void) const
|
||||||
{ return _data[2]; }
|
{ return data()[2]; }
|
||||||
/// Access the z component
|
/// Access the z component
|
||||||
T& z(void)
|
T& z(void)
|
||||||
{ return _data[2]; }
|
{ return data()[2]; }
|
||||||
|
|
||||||
/// Get the data pointer
|
/// Get the data pointer
|
||||||
const T* data(void) const
|
using SGVec3Storage<T>::data;
|
||||||
{ return _data; }
|
|
||||||
/// Get the data pointer
|
|
||||||
T* data(void)
|
|
||||||
{ return _data; }
|
|
||||||
|
|
||||||
/// Readonly interface function to ssg's sgVec3/sgdVec3
|
/// Readonly interface function to ssg's sgVec3/sgdVec3
|
||||||
const T (&sg(void) const)[3]
|
const T (&sg(void) const)[3]
|
||||||
{ return _data; }
|
{ return data(); }
|
||||||
/// Interface function to ssg's sgVec3/sgdVec3
|
/// Interface function to ssg's sgVec3/sgdVec3
|
||||||
T (&sg(void))[3]
|
T (&sg(void))[3]
|
||||||
{ return _data; }
|
{ return data(); }
|
||||||
|
|
||||||
|
/// Interface function to osg's Vec3*
|
||||||
|
using SGVec3Storage<T>::osg;
|
||||||
|
|
||||||
/// Inplace addition
|
/// Inplace addition
|
||||||
SGVec3& operator+=(const SGVec3& v)
|
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
|
/// Inplace subtraction
|
||||||
SGVec3& operator-=(const SGVec3& v)
|
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
|
/// Inplace scalar multiplication
|
||||||
template<typename S>
|
template<typename S>
|
||||||
SGVec3& operator*=(S 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
|
/// Inplace scalar multiplication by 1/s
|
||||||
template<typename S>
|
template<typename S>
|
||||||
SGVec3& operator/=(S s)
|
SGVec3& operator/=(S s)
|
||||||
@@ -125,11 +171,54 @@ public:
|
|||||||
static SGVec3 e3(void)
|
static SGVec3 e3(void)
|
||||||
{ return SGVec3(0, 0, 1); }
|
{ return SGVec3(0, 0, 1); }
|
||||||
|
|
||||||
private:
|
/// Constructor. Initialize by a geodetic coordinate
|
||||||
/// The actual data
|
/// Note that this conversion is relatively expensive to compute
|
||||||
T _data[3];
|
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 ...
|
/// Unary +, do nothing ...
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -172,6 +261,73 @@ SGVec3<T>
|
|||||||
operator*(const SGVec3<T>& v, S s)
|
operator*(const SGVec3<T>& v, S s)
|
||||||
{ return SGVec3<T>(s*v(0), s*v(1), s*v(2)); }
|
{ 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
|
/// Scalar dot product
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -201,6 +357,13 @@ T
|
|||||||
norm1(const SGVec3<T>& v)
|
norm1(const SGVec3<T>& v)
|
||||||
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)); }
|
{ 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
|
/// Vector cross product
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -212,6 +375,31 @@ cross(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
|||||||
v1(0)*v2(1) - v1(1)*v2(0));
|
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
|
/// The euclidean norm of the vector, that is what most people call length
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -233,6 +421,43 @@ bool
|
|||||||
operator!=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
operator!=(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
||||||
{ return ! (v1 == 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
|
/// Return true if equal to the relative tolerance tol
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -257,6 +482,20 @@ equivalent(const SGVec3<T>& v1, const SGVec3<T>& v2)
|
|||||||
return equivalent(v1, v2, tol, tol);
|
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
|
#ifndef NDEBUG
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
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)
|
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec3<T>& v)
|
||||||
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << " ]"; }
|
{ 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
|
inline
|
||||||
SGVec3f
|
SGVec3f
|
||||||
toVec3f(const SGVec3d& v)
|
toVec3f(const SGVec3d& v)
|
||||||
|
|||||||
+218
-38
@@ -18,9 +18,58 @@
|
|||||||
#ifndef SGVec4_H
|
#ifndef SGVec4_H
|
||||||
#define 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
|
/// 4D Vector Class
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGVec4 {
|
class SGVec4 : protected SGVec4Storage<T> {
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
|
|
||||||
@@ -33,82 +82,86 @@ public:
|
|||||||
/// uninitialized values in the debug build very fast ...
|
/// uninitialized values in the debug build very fast ...
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
for (unsigned i = 0; i < 4; ++i)
|
for (unsigned i = 0; i < 4; ++i)
|
||||||
_data[i] = SGLimits<T>::quiet_NaN();
|
data()[i] = SGLimits<T>::quiet_NaN();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/// Constructor. Initialize by the given values
|
/// Constructor. Initialize by the given values
|
||||||
SGVec4(T x, T y, T z, T w)
|
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,
|
/// Constructor. Initialize by the content of a plain array,
|
||||||
/// make sure it has at least 3 elements
|
/// make sure it has at least 3 elements
|
||||||
explicit SGVec4(const T* d)
|
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
|
/// Access by index, the index is unchecked
|
||||||
const T& operator()(unsigned i) const
|
const T& operator()(unsigned i) const
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
/// Access by index, the index is unchecked
|
/// Access by index, the index is unchecked
|
||||||
T& operator()(unsigned i)
|
T& operator()(unsigned i)
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
|
|
||||||
/// Access raw data by index, the index is unchecked
|
/// Access raw data by index, the index is unchecked
|
||||||
const T& operator[](unsigned i) const
|
const T& operator[](unsigned i) const
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
/// Access raw data by index, the index is unchecked
|
/// Access raw data by index, the index is unchecked
|
||||||
T& operator[](unsigned i)
|
T& operator[](unsigned i)
|
||||||
{ return _data[i]; }
|
{ return data()[i]; }
|
||||||
|
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
const T& x(void) const
|
const T& x(void) const
|
||||||
{ return _data[0]; }
|
{ return data()[0]; }
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
T& x(void)
|
T& x(void)
|
||||||
{ return _data[0]; }
|
{ return data()[0]; }
|
||||||
/// Access the y component
|
/// Access the y component
|
||||||
const T& y(void) const
|
const T& y(void) const
|
||||||
{ return _data[1]; }
|
{ return data()[1]; }
|
||||||
/// Access the y component
|
/// Access the y component
|
||||||
T& y(void)
|
T& y(void)
|
||||||
{ return _data[1]; }
|
{ return data()[1]; }
|
||||||
/// Access the z component
|
/// Access the z component
|
||||||
const T& z(void) const
|
const T& z(void) const
|
||||||
{ return _data[2]; }
|
{ return data()[2]; }
|
||||||
/// Access the z component
|
/// Access the z component
|
||||||
T& z(void)
|
T& z(void)
|
||||||
{ return _data[2]; }
|
{ return data()[2]; }
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
const T& w(void) const
|
const T& w(void) const
|
||||||
{ return _data[3]; }
|
{ return data()[3]; }
|
||||||
/// Access the x component
|
/// Access the x component
|
||||||
T& w(void)
|
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
|
/// Readonly interface function to ssg's sgVec4/sgdVec4
|
||||||
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
|
|
||||||
const T (&sg(void) const)[4]
|
const T (&sg(void) const)[4]
|
||||||
{ return _data; }
|
{ return data(); }
|
||||||
/// Interface function to ssg's sgVec3/sgdVec3
|
/// Interface function to ssg's sgVec4/sgdVec4
|
||||||
T (&sg(void))[4]
|
T (&sg(void))[4]
|
||||||
{ return _data; }
|
{ return data(); }
|
||||||
|
|
||||||
|
/// Interface function to osg's Vec4*
|
||||||
|
using SGVec4Storage<T>::osg;
|
||||||
|
|
||||||
/// Inplace addition
|
/// Inplace addition
|
||||||
SGVec4& operator+=(const SGVec4& v)
|
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
|
/// Inplace subtraction
|
||||||
SGVec4& operator-=(const SGVec4& v)
|
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
|
/// Inplace scalar multiplication
|
||||||
template<typename S>
|
template<typename S>
|
||||||
SGVec4& operator*=(S 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
|
/// Inplace scalar multiplication by 1/s
|
||||||
template<typename S>
|
template<typename S>
|
||||||
SGVec4& operator/=(S s)
|
SGVec4& operator/=(S s)
|
||||||
@@ -126,10 +179,6 @@ public:
|
|||||||
{ return SGVec4(0, 0, 1, 0); }
|
{ return SGVec4(0, 0, 1, 0); }
|
||||||
static SGVec4 e4(void)
|
static SGVec4 e4(void)
|
||||||
{ return SGVec4(0, 0, 0, 1); }
|
{ return SGVec4(0, 0, 0, 1); }
|
||||||
|
|
||||||
private:
|
|
||||||
/// The actual data
|
|
||||||
T _data[4];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Unary +, do nothing ...
|
/// Unary +, do nothing ...
|
||||||
@@ -174,6 +223,79 @@ SGVec4<T>
|
|||||||
operator*(const SGVec4<T>& v, S s)
|
operator*(const SGVec4<T>& v, S s)
|
||||||
{ return SGVec4<T>(s*v(0), s*v(1), s*v(2), s*v(3)); }
|
{ 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
|
/// Scalar dot product
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -203,6 +325,13 @@ T
|
|||||||
norm1(const SGVec4<T>& v)
|
norm1(const SGVec4<T>& v)
|
||||||
{ return fabs(v(0)) + fabs(v(1)) + fabs(v(2)) + fabs(v(3)); }
|
{ 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
|
/// The euclidean norm of the vector, that is what most people call length
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -224,6 +353,47 @@ bool
|
|||||||
operator!=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
operator!=(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
||||||
{ return ! (v1 == 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
|
/// Return true if equal to the relative tolerance tol
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
@@ -248,6 +418,20 @@ equivalent(const SGVec4<T>& v1, const SGVec4<T>& v2)
|
|||||||
return equivalent(v1, v2, tol, tol);
|
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
|
#ifndef NDEBUG
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
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)
|
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGVec4<T>& v)
|
||||||
{ return s << "[ " << v(0) << ", " << v(1) << ", " << v(2) << ", " << v(3) << " ]"; }
|
{ 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
|
inline
|
||||||
SGVec4f
|
SGVec4f
|
||||||
toVec4f(const SGVec4d& v)
|
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 <simgear/compiler.h>
|
||||||
|
|
||||||
#include <stdlib.h> // for exit()
|
|
||||||
|
|
||||||
#include STL_STRING
|
#include STL_STRING
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
#include <simgear/misc/sgstream.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
#include "interpolater.hxx"
|
#include "interpolater.hxx"
|
||||||
|
|
||||||
@@ -38,22 +37,29 @@ SG_USING_STD(string);
|
|||||||
|
|
||||||
// Constructor -- starts with an empty table.
|
// Constructor -- starts with an empty table.
|
||||||
SGInterpTable::SGInterpTable()
|
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
|
// Constructor -- loads the interpolation table from the specified
|
||||||
// file
|
// file
|
||||||
SGInterpTable::SGInterpTable( const string& file )
|
SGInterpTable::SGInterpTable( const string& file )
|
||||||
: size(0)
|
|
||||||
{
|
{
|
||||||
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
||||||
|
|
||||||
sg_gzifstream in( file );
|
sg_gzifstream in( file );
|
||||||
if ( !in.is_open() ) {
|
if ( !in.is_open() ) {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
|
||||||
exit(-1);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
in >> skipcomment;
|
in >> skipcomment;
|
||||||
@@ -61,8 +67,7 @@ SGInterpTable::SGInterpTable( const string& file )
|
|||||||
double ind, dep;
|
double ind, dep;
|
||||||
in >> ind >> dep;
|
in >> ind >> dep;
|
||||||
in >> skipws;
|
in >> skipws;
|
||||||
table.push_back(Entry(ind, dep));
|
_table[ind] = dep;
|
||||||
size++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,51 +75,42 @@ SGInterpTable::SGInterpTable( const string& file )
|
|||||||
// Add an entry to the table.
|
// Add an entry to the table.
|
||||||
void SGInterpTable::addEntry (double ind, double dep)
|
void SGInterpTable::addEntry (double ind, double dep)
|
||||||
{
|
{
|
||||||
table.push_back(Entry(ind,dep));
|
_table[ind] = dep;
|
||||||
size++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Given an x value, linearly interpolate the y value from the table
|
// Given an x value, linearly interpolate the y value from the table
|
||||||
double SGInterpTable::interpolate(double x) const
|
double SGInterpTable::interpolate(double x) const
|
||||||
{
|
{
|
||||||
int i;
|
// Empty table??
|
||||||
double y;
|
if (_table.empty())
|
||||||
|
return 0;
|
||||||
if (size == 0.0) {
|
|
||||||
return 0.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.
|
||||||
i = 0;
|
// use the last entry
|
||||||
|
if (upBoundIt == _table.end())
|
||||||
while ( (i < size) && (x > table[i].ind) ) {
|
return _table.rbegin()->second;
|
||||||
// cout << " i = " << i << " table[i].ind = " << table[i].ind << endl;
|
|
||||||
// cout << " size = " << size << endl;
|
// points to the first key must be lower
|
||||||
i++;
|
// use the first entry
|
||||||
}
|
if (upBoundIt == _table.begin())
|
||||||
|
return upBoundIt->second;
|
||||||
// printf ("i = %d ", i);
|
|
||||||
|
// we know that we do not stand at the beginning, so it is safe to do so
|
||||||
if ( i <= 0 ) {
|
Table::const_iterator loBoundIt = upBoundIt;
|
||||||
SG_LOG( SG_MATH, SG_DEBUG,
|
--loBoundIt;
|
||||||
"interpolate(): lookup error, x to small = " << x );
|
|
||||||
return table[0].dep;
|
// Just do linear interpolation.
|
||||||
}
|
double loBound = loBoundIt->first;
|
||||||
|
double upBound = upBoundIt->first;
|
||||||
// cout << " table[size-1].ind = " << table[size-1].ind << endl;
|
double loVal = loBoundIt->second;
|
||||||
if ( i >= size ) {
|
double upVal = upBoundIt->second;
|
||||||
SG_LOG( SG_MATH, SG_DEBUG,
|
|
||||||
"interpolate(): lookup error, x to big = " << x );
|
// division by zero should not happen since the std::map
|
||||||
return table[size-1].dep;
|
// 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);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,14 @@
|
|||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include <vector>
|
#include "simgear/structure/SGReferenced.hxx"
|
||||||
SG_USING_STD(vector);
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include STL_STRING
|
#include STL_STRING
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
class SGPropertyNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that provids a simple linear 2d interpolation lookup table.
|
* 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
|
* independant variable must be strictly ascending. The dependent
|
||||||
* variable can be anything.
|
* variable can be anything.
|
||||||
*/
|
*/
|
||||||
class SGInterpTable {
|
class SGInterpTable : public SGReferenced {
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,6 +58,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
SGInterpTable();
|
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.
|
* Constructor. Loads the interpolation table from the specified file.
|
||||||
* @param file name of interpolation file
|
* @param file name of interpolation file
|
||||||
@@ -95,6 +90,10 @@ public:
|
|||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~SGInterpTable();
|
~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 fromSGGeod(const SGGeod& geod);
|
||||||
static Point3D fromSGGeoc(const SGGeoc& geoc);
|
static Point3D fromSGGeoc(const SGGeoc& geoc);
|
||||||
static Point3D fromSGVec3(const SGVec3<double>& cart);
|
static Point3D fromSGVec3(const SGVec3<double>& cart);
|
||||||
|
static Point3D fromSGVec3(const SGVec3<float>& cart);
|
||||||
|
static Point3D fromSGVec2(const SGVec2<double>& cart);
|
||||||
|
|
||||||
// Assignment operators
|
// Assignment operators
|
||||||
|
|
||||||
@@ -132,6 +134,10 @@ public:
|
|||||||
SGGeod toSGGeod(void) const;
|
SGGeod toSGGeod(void) const;
|
||||||
SGGeoc toSGGeoc(void) const;
|
SGGeoc toSGGeoc(void) const;
|
||||||
|
|
||||||
|
SGVec3d toSGVec3d(void) const;
|
||||||
|
SGVec3f toSGVec3f(void) const;
|
||||||
|
SGVec2f toSGVec2f(void) const;
|
||||||
|
|
||||||
// friends
|
// friends
|
||||||
friend Point3D operator - (const Point3D& p); // -p1
|
friend Point3D operator - (const Point3D& p); // -p1
|
||||||
friend bool operator == (const Point3D& a, const Point3D& b); // p1 == p2?
|
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;
|
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
|
// ASSIGNMENT OPERATORS
|
||||||
|
|
||||||
inline Point3D& Point3D::operator = (const Point3D& p)
|
inline Point3D& Point3D::operator = (const Point3D& p)
|
||||||
@@ -341,6 +365,21 @@ inline SGGeoc Point3D::toSGGeoc(void) const
|
|||||||
return geoc;
|
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
|
// FRIENDS
|
||||||
|
|
||||||
inline Point3D operator - (const Point3D& a)
|
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
|
// and az2. Lat, lon, and azimuth are in degrees. distance in meters
|
||||||
int geo_direct_wgs_84 ( double alt, double lat1,
|
int geo_direct_wgs_84 ( double lat1, double lon1, double az1,
|
||||||
double lon1, double az1,
|
|
||||||
double s, double *lat2, double *lon2,
|
double s, double *lat2, double *lon2,
|
||||||
double *az2 )
|
double *az2 )
|
||||||
{
|
{
|
||||||
@@ -160,16 +159,15 @@ int geo_direct_wgs_84 ( double alt, double lat1,
|
|||||||
double dM = a*M0(e2) - s;
|
double dM = a*M0(e2) - s;
|
||||||
double paz = ( phi1 < 0.0 ? 180.0 : 0.0 );
|
double paz = ( phi1 < 0.0 ? 180.0 : 0.0 );
|
||||||
double zero = 0.0f;
|
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.
|
// az1, az2 and distance (s). Lat, lon, and azimuth are in degrees.
|
||||||
// distance in meters
|
// distance in meters
|
||||||
int geo_inverse_wgs_84( double alt, double lat1,
|
int geo_inverse_wgs_84( double lat1, double lon1, double lat2,
|
||||||
double lon1, double lat2,
|
|
||||||
double lon2, double *az1, double *az2,
|
double lon2, double *az1, double *az2,
|
||||||
double *s )
|
double *s )
|
||||||
{
|
{
|
||||||
@@ -192,14 +190,14 @@ int geo_inverse_wgs_84( double alt, double lat1,
|
|||||||
return 0;
|
return 0;
|
||||||
} else if( fabs(cosphi1) < testv ) {
|
} else if( fabs(cosphi1) < testv ) {
|
||||||
// initial point is polar
|
// 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
|
k = k; // avoid compiler error since return result is unused
|
||||||
b = *az1; *az1 = *az2; *az2 = b;
|
b = *az1; *az1 = *az2; *az2 = b;
|
||||||
return 0;
|
return 0;
|
||||||
} else if( fabs(cosphi2) < testv ) {
|
} else if( fabs(cosphi2) < testv ) {
|
||||||
// terminal point is polar
|
// terminal point is polar
|
||||||
double _lon1 = lon1 + 180.0f;
|
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 );
|
az1, az2, s );
|
||||||
k = k; // avoid compiler error since return result is unused
|
k = k; // avoid compiler error since return result is unused
|
||||||
*s /= 2.0;
|
*s /= 2.0;
|
||||||
@@ -211,8 +209,8 @@ int geo_inverse_wgs_84( double alt, double lat1,
|
|||||||
{
|
{
|
||||||
// Geodesic passes through the pole (antipodal)
|
// Geodesic passes through the pole (antipodal)
|
||||||
double s1,s2;
|
double s1,s2;
|
||||||
geo_inverse_wgs_84( alt, lat1,lon1, lat1,lon2, az1,az2, &s1 );
|
geo_inverse_wgs_84( lat1,lon1, lat1,lon2, az1,az2, &s1 );
|
||||||
geo_inverse_wgs_84( alt, lat2,lon2, lat1,lon2, az1,az2, &s2 );
|
geo_inverse_wgs_84( lat2,lon2, lat1,lon2, az1,az2, &s2 );
|
||||||
*az2 = *az1;
|
*az2 = *az1;
|
||||||
*s = s1 + s2;
|
*s = s1 + s2;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+54
-20
@@ -4,18 +4,6 @@
|
|||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
#include "SGMath.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
|
* Convert from geocentric coordinates to geodetic coordinates
|
||||||
* @param lat_geoc (in) Geocentric latitude, radians, + = North
|
* @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)
|
double *sl_radius, double *lat_geoc)
|
||||||
{
|
{
|
||||||
SGVec3<double> cart;
|
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;
|
SGGeoc geoc;
|
||||||
SGGeodesy::SGCartToGeoc(cart, geoc);
|
SGGeodesy::SGCartToGeoc(cart, geoc);
|
||||||
*lat_geoc = geoc.getLatitudeRad();
|
*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,
|
* Given a starting position and an offset radial and distance,
|
||||||
* calculate an ending positon on a wgs84 ellipsoid.
|
* calculate an ending positon on a wgs84 ellipsoid.
|
||||||
* @param alt (in) meters
|
* @param alt (in) meters (unused)
|
||||||
* @param lat1 (in) degrees
|
* @param lat1 (in) degrees
|
||||||
* @param lon1 (in) degrees
|
* @param lon1 (in) degrees
|
||||||
* @param az1 (in) degrees
|
* @param az1 (in) degrees
|
||||||
@@ -139,16 +128,39 @@ inline Point3D sgGeodToCart(const Point3D& geod)
|
|||||||
* @param lon2 (out) degrees
|
* @param lon2 (out) degrees
|
||||||
* @param az2 (out) return course in degrees
|
* @param az2 (out) return course in degrees
|
||||||
*/
|
*/
|
||||||
int geo_direct_wgs_84 ( double alt, double lat1,
|
int geo_direct_wgs_84 ( double lat1, double lon1, double az1,
|
||||||
double lon1, double az1,
|
|
||||||
double s, double *lat2, double *lon2,
|
double s, double *lat2, double *lon2,
|
||||||
double *az2 );
|
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
|
* Given an altitude and two sets of (lat, lon) calculate great circle
|
||||||
* distance between them as well as the starting and ending azimuths.
|
* 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 lat1 (in) degrees
|
||||||
* @param lon1 (in) degrees
|
* @param lon1 (in) degrees
|
||||||
* @param lat2 (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 az2 (out) end heading degrees
|
||||||
* @param s (out) distance meters
|
* @param s (out) distance meters
|
||||||
*/
|
*/
|
||||||
int geo_inverse_wgs_84( double alt, double lat1,
|
int geo_inverse_wgs_84( double lat1, double lon1, double lat2,
|
||||||
double lon1, double lat2,
|
|
||||||
double lon2, double *az1, double *az2,
|
double lon2, double *az1, double *az2,
|
||||||
double *s );
|
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
|
#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 ) {
|
void SGPath::create_dir( mode_t mode ) {
|
||||||
string_list dirlist = sgPathSplit(dir());
|
string_list dirlist = sgPathSplit(dir());
|
||||||
|
if ( dirlist.empty() )
|
||||||
|
return;
|
||||||
string path = dirlist[0];
|
string path = dirlist[0];
|
||||||
string_list path_elements = sgPathBranchSplit(path);
|
string_list path_elements = sgPathBranchSplit(path);
|
||||||
bool absolute = !path.empty() && path[0] == sgDirPathSep;
|
bool absolute = !path.empty() && path[0] == sgDirPathSep;
|
||||||
|
|||||||
@@ -2,26 +2,12 @@ includedir = @includedir@/nasal
|
|||||||
|
|
||||||
lib_LIBRARIES = libsgnasal.a
|
lib_LIBRARIES = libsgnasal.a
|
||||||
|
|
||||||
include_HEADERS = nasal.h
|
include_HEADERS = nasal.h naref.h
|
||||||
|
|
||||||
libsgnasal_a_SOURCES = \
|
libsgnasal_a_SOURCES = bitslib.c code.c code.h codegen.c data.h gc.c \
|
||||||
code.c code.h \
|
hash.c iolib.c iolib.h lex.c lib.c mathlib.c \
|
||||||
codegen.c \
|
misc.c naref.h nasal.h parse.c parse.h string.c \
|
||||||
data.h \
|
thread-posix.c thread-win32.c threadlib.c \
|
||||||
gc.c \
|
utf8lib.c vector.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
|
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)
|
INCLUDES = -I$(top_srcdir)
|
||||||
|
|||||||
+10
-17
@@ -5,10 +5,10 @@
|
|||||||
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch
|
// bits (i.e. an unsigned int). Using a 64 bit integer would stretch
|
||||||
// that beyond what is representable in the double result, but
|
// that beyond what is representable in the double result, but
|
||||||
// requires portability work.
|
// requires portability work.
|
||||||
|
#define MSK(n) (1 << (7 - ((n) & 7)))
|
||||||
#define BIT(s,l,n) s[l-1-((n)>>3)] & (1<<((n)&7))
|
#define BIT(s,l,n) s[(n)>>3] & MSK(n)
|
||||||
#define CLRB(s,l,n) s[l-1-((n)>>3)] &= ~(1<<((n)&7))
|
#define CLRB(s,l,n) s[(n)>>3] &= ~MSK(n)
|
||||||
#define SETB(s,l,n) s[l-1-((n)>>3)] |= 1<<((n)&7)
|
#define SETB(s,l,n) s[(n)>>3] |= MSK(n)
|
||||||
|
|
||||||
static unsigned int fld(naContext c, unsigned char* s,
|
static unsigned int fld(naContext c, unsigned char* s,
|
||||||
int slen, int bit, int flen)
|
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)
|
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 bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
||||||
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
||||||
unsigned int f;
|
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)
|
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 bit = argc > 1 ? (int)naNumValue(args[1]).num : -1;
|
||||||
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
int len = argc > 2 ? (int)naNumValue(args[2]).num : -1;
|
||||||
naRef val = argc > 3 ? naNumValue(args[3]) : naNil();
|
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);
|
return naStr_buf(naNewString(c), (int)len.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
static naCFuncItem funcs[] = {
|
||||||
{ "sfld", f_sfld },
|
{ "sfld", f_sfld },
|
||||||
{ "fld", f_fld },
|
{ "fld", f_fld },
|
||||||
{ "setfld", f_setfld },
|
{ "setfld", f_setfld },
|
||||||
{ "buf", f_buf },
|
{ "buf", f_buf },
|
||||||
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
naRef naBitsLib(naContext c)
|
naRef naInit_bits(naContext c)
|
||||||
{
|
{
|
||||||
naRef namespace = naNewHash(c);
|
return naGenLib(c, funcs);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+251
-160
@@ -1,11 +1,14 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
#include "nasal.h"
|
#include "nasal.h"
|
||||||
#include "code.h"
|
#include "code.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Debugging stuff. ////////////////////////////////////////////////////
|
// Debugging stuff. ////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
//#define DEBUG_NASAL
|
//#define INTERPRETER_DUMP
|
||||||
#if !defined(DEBUG_NASAL)
|
#if !defined(INTERPRETER_DUMP)
|
||||||
# define DBG(expr) /* noop */
|
# define DBG(expr) /* noop */
|
||||||
#else
|
#else
|
||||||
# define DBG(expr) expr
|
# define DBG(expr) expr
|
||||||
@@ -17,21 +20,44 @@ void printOpDEBUG(int ip, int op);
|
|||||||
void printStackDEBUG(struct Context* ctx);
|
void printStackDEBUG(struct Context* ctx);
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define vsnprintf _vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
struct Globals* globals = 0;
|
struct Globals* globals = 0;
|
||||||
|
|
||||||
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
|
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
|
||||||
|
|
||||||
#define ERR(c, msg) naRuntimeError((c),(msg))
|
#define ERR(c, msg) naRuntimeError((c),(msg))
|
||||||
void naRuntimeError(struct Context* c, char* msg)
|
void naRuntimeError(struct Context* c, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
c->error = msg;
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(c->error, sizeof(c->error), fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
longjmp(c->jumpHandle, 1);
|
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)
|
static int boolify(struct Context* ctx, naRef r)
|
||||||
{
|
{
|
||||||
if(IS_NUM(r)) return r.num != 0;
|
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)) {
|
if(IS_STR(r)) {
|
||||||
double d;
|
double d;
|
||||||
if(naStr_len(r) == 0) return 0;
|
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);
|
int i = (int)numify(ctx, idx);
|
||||||
if(i < 0) i += naVec_size(vec);
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +101,9 @@ static int checkStr(struct Context* ctx, naRef str, naRef idx)
|
|||||||
{
|
{
|
||||||
int i = (int)numify(ctx, idx);
|
int i = (int)numify(ctx, idx);
|
||||||
if(i < 0) i += naStr_len(str);
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,8 +112,7 @@ static naRef containerGet(struct Context* ctx, naRef box, naRef key)
|
|||||||
naRef result = naNil();
|
naRef result = naNil();
|
||||||
if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
|
if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
|
||||||
if(IS_HASH(box)) {
|
if(IS_HASH(box)) {
|
||||||
if(!naHash_get(box, key, &result))
|
naHash_get(box, key, &result);
|
||||||
ERR(ctx, "undefined value in container");
|
|
||||||
} else if(IS_VEC(box)) {
|
} else if(IS_VEC(box)) {
|
||||||
result = naVec_get(box, checkVec(ctx, box, key));
|
result = naVec_get(box, checkVec(ctx, box, key));
|
||||||
} else if(IS_STR(box)) {
|
} 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_HASH(box)) naHash_set(box, key, val);
|
||||||
else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
|
else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
|
||||||
else if(IS_STR(box)) {
|
else if(IS_STR(box)) {
|
||||||
if(box.ref.ptr.str->hashcode)
|
if(PTR(box).str->hashcode)
|
||||||
ERR(ctx, "cannot change immutable string");
|
ERR(ctx, "cannot change immutable string");
|
||||||
naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
|
naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
|
||||||
} else ERR(ctx, "insert into non-container");
|
} else ERR(ctx, "insert into non-container");
|
||||||
@@ -128,7 +157,8 @@ static void initContext(struct Context* c)
|
|||||||
c->callParent = 0;
|
c->callParent = 0;
|
||||||
c->callChild = 0;
|
c->callChild = 0;
|
||||||
c->dieArg = naNil();
|
c->dieArg = naNil();
|
||||||
c->error = 0;
|
c->error[0] = 0;
|
||||||
|
c->userData = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initGlobals()
|
static void initGlobals()
|
||||||
@@ -191,47 +221,46 @@ struct Context* naNewContext()
|
|||||||
return c;
|
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)
|
void naFreeContext(struct Context* c)
|
||||||
{
|
{
|
||||||
c->ntemps = 0;
|
c->ntemps = 0;
|
||||||
|
if(c->callChild) naFreeContext(c->callChild);
|
||||||
|
if(c->callParent) c->callParent->callChild = 0;
|
||||||
LOCK();
|
LOCK();
|
||||||
c->nextFree = globals->freeContexts;
|
c->nextFree = globals->freeContexts;
|
||||||
globals->freeContexts = c;
|
globals->freeContexts = c;
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
// Note that opTop is incremented separately, to avoid situations
|
||||||
/*
|
// where the "r" expression also references opTop. The SGI compiler
|
||||||
* This is the original code which might not work properly on all
|
// is known to have issues with such code.
|
||||||
* platforms since it allows one to work on the same variable in one
|
#define PUSH(r) do { \
|
||||||
* statement without the prior knowledge how this will behave.
|
|
||||||
*
|
|
||||||
* e.g. ctx->opStack[ctx->opTop++] = ctx->opStack[ctx->opTop-1];
|
|
||||||
* ^^^^^ ^^^^^
|
|
||||||
*/
|
|
||||||
# define PUSH(r) do { \
|
|
||||||
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \
|
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \
|
||||||
ctx->opStack[ctx->opTop++] = r; \
|
ctx->opStack[ctx->opTop] = r; \
|
||||||
|
ctx->opTop++; \
|
||||||
} while(0)
|
} 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)
|
static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
||||||
{
|
{
|
||||||
int i;
|
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
|
// 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++)
|
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]);
|
&c->constants[c->argSyms[i]], &args[i]);
|
||||||
args += c->nArgs;
|
args += c->nArgs;
|
||||||
nargs -= 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]];
|
naRef val = nargs > 0 ? args[i] : c->constants[c->optArgVals[i]];
|
||||||
if(IS_CODE(val))
|
if(IS_CODE(val))
|
||||||
val = bindFunction(ctx, &ctx->fStack[ctx->fTop-2], 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);
|
&val);
|
||||||
}
|
}
|
||||||
args += c->nOptArgs;
|
args += c->nOptArgs;
|
||||||
@@ -247,12 +276,12 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
|
|||||||
naRef argsv = naNewVector(ctx);
|
naRef argsv = naNewVector(ctx);
|
||||||
naVec_setsize(argsv, nargs > 0 ? nargs : 0);
|
naVec_setsize(argsv, nargs > 0 ? nargs : 0);
|
||||||
for(i=0; i<nargs; i++)
|
for(i=0; i<nargs; i++)
|
||||||
argsv.ref.ptr.vec->rec->array[i] = *args++;
|
PTR(argsv).vec->rec->array[i] = *args++;
|
||||||
naHash_newsym(f->locals.ref.ptr.hash, &c->restArgSym, &argsv);
|
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;
|
naRef *frame;
|
||||||
struct Frame* f;
|
struct Frame* f;
|
||||||
@@ -263,20 +292,20 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
|||||||
if(!IS_FUNC(frame[0]))
|
if(!IS_FUNC(frame[0]))
|
||||||
ERR(ctx, "function/method call invoked on uncallable object");
|
ERR(ctx, "function/method call invoked on uncallable object");
|
||||||
|
|
||||||
// Just do native calls right here, and don't touch the stack
|
ctx->opFrame = ctx->opTop - (nargs + 1 + mcall);
|
||||||
// frames; return the current one (unless it's a tail call!).
|
|
||||||
if(frame[0].ref.ptr.func->code.ref.ptr.obj->type == T_CCODE) {
|
// Just do native calls right here
|
||||||
|
if(PTR(PTR(frame[0]).func->code).obj->type == T_CCODE) {
|
||||||
naRef obj = mcall ? frame[-1] : naNil();
|
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);
|
naRef result = (*fp)(ctx, obj, nargs, frame + 1);
|
||||||
ctx->opTop -= nargs + 1 + mcall;
|
ctx->opTop = ctx->opFrame;
|
||||||
PUSH(result);
|
PUSH(result);
|
||||||
return &(ctx->fStack[ctx->fTop-1]);
|
return &(ctx->fStack[ctx->fTop-1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tail) ctx->fTop--;
|
if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
|
||||||
else if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
|
|
||||||
|
|
||||||
// Note: assign nil first, otherwise the naNew() can cause a GC,
|
// Note: assign nil first, otherwise the naNew() can cause a GC,
|
||||||
// which will now (after fTop++) see the *old* reference as a
|
// which will now (after fTop++) see the *old* reference as a
|
||||||
// markable value!
|
// markable value!
|
||||||
@@ -285,7 +314,7 @@ struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall, int tail)
|
|||||||
f->locals = naNewHash(ctx);
|
f->locals = naNewHash(ctx);
|
||||||
f->func = frame[0];
|
f->func = frame[0];
|
||||||
f->ip = 0;
|
f->ip = 0;
|
||||||
f->bp = ctx->opTop - (nargs + 1 + mcall);
|
f->bp = ctx->opFrame;
|
||||||
|
|
||||||
if(mcall)
|
if(mcall)
|
||||||
naHash_set(f->locals, globals->meRef, frame[-1]);
|
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;
|
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)
|
static naRef evalEquality(int op, naRef ra, naRef rb)
|
||||||
{
|
{
|
||||||
int result = naEqual(ra, rb);
|
int result = naEqual(ra, rb);
|
||||||
return naNum((op==OP_EQ) ? result : !result);
|
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
|
// 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.
|
// the stack, it needs to be bound with the lexical context.
|
||||||
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
|
static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
|
||||||
{
|
{
|
||||||
naRef result = naNewFunc(ctx, code);
|
naRef result = naNewFunc(ctx, code);
|
||||||
result.ref.ptr.func->namespace = f->locals;
|
PTR(result).func->namespace = f->locals;
|
||||||
result.ref.ptr.func->next = f->func;
|
PTR(result).func->next = f->func;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +362,7 @@ static int getClosure(struct naFunc* c, naRef sym, naRef* result)
|
|||||||
{
|
{
|
||||||
while(c) {
|
while(c) {
|
||||||
if(naHash_get(c->namespace, sym, result)) return 1;
|
if(naHash_get(c->namespace, sym, result)) return 1;
|
||||||
c = c->next.ref.ptr.func;
|
c = PTR(c->next).func;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -336,8 +371,8 @@ static naRef getLocal2(struct Context* ctx, struct Frame* f, naRef sym)
|
|||||||
{
|
{
|
||||||
naRef result;
|
naRef result;
|
||||||
if(!naHash_get(f->locals, sym, &result))
|
if(!naHash_get(f->locals, sym, &result))
|
||||||
if(!getClosure(f->func.ref.ptr.func, sym, &result))
|
if(!getClosure(PTR(f->func).func, sym, &result))
|
||||||
ERR(ctx, "undefined symbol");
|
naRuntimeError(ctx, "undefined symbol: %s", naStr_data(sym));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,14 +380,14 @@ static void getLocal(struct Context* ctx, struct Frame* f,
|
|||||||
naRef* sym, naRef* out)
|
naRef* sym, naRef* out)
|
||||||
{
|
{
|
||||||
struct naFunc* func;
|
struct naFunc* func;
|
||||||
struct naStr* str = sym->ref.ptr.str;
|
struct naStr* str = PTR(*sym).str;
|
||||||
if(naHash_sym(f->locals.ref.ptr.hash, str, out))
|
if(naHash_sym(PTR(f->locals).hash, str, out))
|
||||||
return;
|
return;
|
||||||
func = f->func.ref.ptr.func;
|
func = PTR(f->func).func;
|
||||||
while(func && func->namespace.ref.ptr.hash) {
|
while(func && PTR(func->namespace).hash) {
|
||||||
if(naHash_sym(func->namespace.ref.ptr.hash, str, out))
|
if(naHash_sym(PTR(func->namespace).hash, str, out))
|
||||||
return;
|
return;
|
||||||
func = func->next.ref.ptr.func;
|
func = PTR(func->next).func;
|
||||||
}
|
}
|
||||||
// Now do it again using the more general naHash_get(). This will
|
// Now do it again using the more general naHash_get(). This will
|
||||||
// only be necessary if something has created the value in the
|
// 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)
|
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; }
|
if(c == 0) { return 0; }
|
||||||
else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
|
else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
|
||||||
else { return setClosure(c->next, sym, val); }
|
else { return setClosure(c->next, sym, val); }
|
||||||
@@ -379,39 +414,52 @@ static naRef setSymbol(struct Frame* f, naRef sym, naRef val)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively descend into the parents lists
|
// Funky API: returns null to indicate no member, an empty string to
|
||||||
static int getMember(struct Context* ctx, naRef obj, naRef fld,
|
// indicate success, or a non-empty error message. Works this way so
|
||||||
naRef* result, int count)
|
// 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;
|
naRef p;
|
||||||
if(--count < 0) ERR(ctx, "too many parents");
|
struct VecRec* pv;
|
||||||
if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members");
|
if(--count < 0) return "too many parents";
|
||||||
if(naHash_get(obj, fld, result)) {
|
if(!IS_HASH(obj)) return 0;
|
||||||
return 1;
|
if(naHash_get(obj, field, out)) return "";
|
||||||
} else if(naHash_get(obj, globals->parentsRef, &p)) {
|
if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
|
||||||
if(IS_VEC(p)) {
|
if(!IS_VEC(p)) return "object \"parents\" field not vector";
|
||||||
int i;
|
pv = PTR(p).vec->rec;
|
||||||
struct VecRec* v = p.ref.ptr.vec->rec;
|
for(i=0; i<pv->size; i++) {
|
||||||
for(i=0; i<v->size; i++)
|
const char* err = getMember_r(pv->array[i], field, out, count);
|
||||||
if(getMember(ctx, v->array[i], fld, result, count))
|
if(err) return err; /* either an error or success */
|
||||||
return 1;
|
|
||||||
} else
|
|
||||||
ERR(ctx, "parents field not vector");
|
|
||||||
}
|
}
|
||||||
return 0;
|
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
|
// 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
|
// and index on the stack, increments the index after use, and
|
||||||
// the arguments and pushes a nil if the index is beyond the end.
|
// pushes a nil if the index is beyond the end.
|
||||||
static void evalEach(struct Context* ctx, int useIndex)
|
static void evalEach(struct Context* ctx, int useIndex)
|
||||||
{
|
{
|
||||||
int idx = (int)(ctx->opStack[ctx->opTop-1].num);
|
int idx = (int)(ctx->opStack[ctx->opTop-1].num);
|
||||||
naRef vec = ctx->opStack[ctx->opTop-2];
|
naRef vec = ctx->opStack[ctx->opTop-2];
|
||||||
if(!IS_VEC(vec)) naRuntimeError(ctx, "foreach enumeration of non-vector");
|
if(!IS_VEC(vec)) ERR(ctx, "foreach enumeration of non-vector");
|
||||||
if(!vec.ref.ptr.vec->rec || idx >= vec.ref.ptr.vec->rec->size) {
|
if(!PTR(vec).vec->rec || idx >= PTR(vec).vec->rec->size) {
|
||||||
ctx->opTop -= 2; // pop two values
|
PUSH(endToken());
|
||||||
PUSH(naNil());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx->opStack[ctx->opTop-1].num = idx+1; // modify in place
|
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 POP() ctx->opStack[--ctx->opTop]
|
||||||
#define STK(n) (ctx->opStack[ctx->opTop-(n)])
|
#define STK(n) (ctx->opStack[ctx->opTop-(n)])
|
||||||
#define FIXFRAME() f = &(ctx->fStack[ctx->fTop-1]); \
|
#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)
|
static naRef run(struct Context* ctx)
|
||||||
{
|
{
|
||||||
struct Frame* f;
|
struct Frame* f;
|
||||||
struct naCode* cd;
|
struct naCode* cd;
|
||||||
int op, arg;
|
int op, arg;
|
||||||
naRef a, b, c;
|
naRef a, b;
|
||||||
|
|
||||||
|
ctx->dieArg = naNil();
|
||||||
|
ctx->error[0] = 0;
|
||||||
|
|
||||||
FIXFRAME();
|
FIXFRAME();
|
||||||
|
|
||||||
@@ -455,8 +506,7 @@ static naRef run(struct Context* ctx)
|
|||||||
#define BINOP(expr) do { \
|
#define BINOP(expr) do { \
|
||||||
double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \
|
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)); \
|
double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \
|
||||||
STK(2).ref.reftag = ~NASAL_REFTAG; \
|
SETNUM(STK(2), expr); \
|
||||||
STK(2).num = expr; \
|
|
||||||
ctx->opTop--; } while(0)
|
ctx->opTop--; } while(0)
|
||||||
|
|
||||||
case OP_PLUS: BINOP(l + r); break;
|
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_LTE: BINOP(l <= r ? 1 : 0); break;
|
||||||
case OP_GT: BINOP(l > r ? 1 : 0); break;
|
case OP_GT: BINOP(l > r ? 1 : 0); break;
|
||||||
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
|
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
|
||||||
|
|
||||||
#undef BINOP
|
#undef BINOP
|
||||||
|
|
||||||
case OP_EQ: case OP_NEQ:
|
case OP_EQ: case OP_NEQ:
|
||||||
STK(2) = evalEquality(op, STK(2), STK(1));
|
STK(2) = evalEquality(op, STK(2), STK(1));
|
||||||
ctx->opTop--;
|
ctx->opTop--;
|
||||||
break;
|
break;
|
||||||
case OP_AND: case OP_OR:
|
|
||||||
STK(2) = evalAndOr(ctx, op, STK(2), STK(1));
|
|
||||||
ctx->opTop--;
|
|
||||||
break;
|
|
||||||
case OP_CAT:
|
case OP_CAT:
|
||||||
// stringify can call the GC, so don't take stuff of the stack!
|
STK(2) = evalCat(ctx, STK(2), STK(1));
|
||||||
a = stringify(ctx, ctx->opStack[ctx->opTop-1]);
|
ctx->opTop -= 1;
|
||||||
b = stringify(ctx, ctx->opStack[ctx->opTop-2]);
|
|
||||||
c = naStr_concat(naNewString(ctx), b, a);
|
|
||||||
ctx->opTop -= 2;
|
|
||||||
PUSH(c);
|
|
||||||
break;
|
break;
|
||||||
case OP_NEG:
|
case OP_NEG:
|
||||||
STK(1) = naNum(-numify(ctx, STK(1)));
|
STK(1) = naNum(-numify(ctx, STK(1)));
|
||||||
@@ -506,6 +547,9 @@ static naRef run(struct Context* ctx)
|
|||||||
case OP_PUSHNIL:
|
case OP_PUSHNIL:
|
||||||
PUSH(naNil());
|
PUSH(naNil());
|
||||||
break;
|
break;
|
||||||
|
case OP_PUSHEND:
|
||||||
|
PUSH(endToken());
|
||||||
|
break;
|
||||||
case OP_NEWVEC:
|
case OP_NEWVEC:
|
||||||
PUSH(naNewVector(ctx));
|
PUSH(naNewVector(ctx));
|
||||||
break;
|
break;
|
||||||
@@ -535,8 +579,7 @@ static naRef run(struct Context* ctx)
|
|||||||
ctx->opTop--;
|
ctx->opTop--;
|
||||||
break;
|
break;
|
||||||
case OP_MEMBER:
|
case OP_MEMBER:
|
||||||
if(!getMember(ctx, STK(1), CONSTARG(), &STK(1), 64))
|
getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
|
||||||
ERR(ctx, "no such member");
|
|
||||||
break;
|
break;
|
||||||
case OP_SETMEMBER:
|
case OP_SETMEMBER:
|
||||||
if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members");
|
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];
|
f->ip = cd->byteCode[f->ip];
|
||||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||||
break;
|
break;
|
||||||
case OP_JIFNIL:
|
case OP_JIFEND:
|
||||||
arg = ARG();
|
arg = ARG();
|
||||||
if(IS_NIL(STK(1))) {
|
if(IS_END(STK(1))) {
|
||||||
ctx->opTop--; // Pops **ONLY** if it's nil!
|
ctx->opTop--; // Pops **ONLY** if it's nil!
|
||||||
f->ip = arg;
|
f->ip = arg;
|
||||||
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
DBG(printf(" [Jump to: %d]\n", f->ip);)
|
||||||
}
|
}
|
||||||
break;
|
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:
|
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();
|
arg = ARG();
|
||||||
if(!boolify(ctx, POP())) {
|
if(!boolify(ctx, POP())) {
|
||||||
f->ip = arg;
|
f->ip = arg;
|
||||||
@@ -579,23 +636,17 @@ static naRef run(struct Context* ctx)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_FCALL:
|
case OP_FCALL:
|
||||||
f = setupFuncall(ctx, ARG(), 0, 0);
|
f = setupFuncall(ctx, ARG(), 0);
|
||||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
cd = PTR(PTR(f->func).func->code).code;
|
||||||
break;
|
|
||||||
case OP_FTAIL:
|
|
||||||
f = setupFuncall(ctx, ARG(), 0, 1);
|
|
||||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
|
||||||
break;
|
break;
|
||||||
case OP_MCALL:
|
case OP_MCALL:
|
||||||
f = setupFuncall(ctx, ARG(), 1, 0);
|
f = setupFuncall(ctx, ARG(), 1);
|
||||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
cd = PTR(PTR(f->func).func->code).code;
|
||||||
break;
|
|
||||||
case OP_MTAIL:
|
|
||||||
f = setupFuncall(ctx, ARG(), 1, 1);
|
|
||||||
cd = f->func.ref.ptr.func->code.ref.ptr.code;
|
|
||||||
break;
|
break;
|
||||||
case OP_RETURN:
|
case OP_RETURN:
|
||||||
a = STK(1);
|
a = STK(1);
|
||||||
|
ctx->dieArg = naNil();
|
||||||
|
if(ctx->callChild) naFreeContext(ctx->callChild);
|
||||||
if(--ctx->fTop <= 0) return a;
|
if(--ctx->fTop <= 0) return a;
|
||||||
ctx->opTop = f->bp + 1; // restore the correct opstack frame!
|
ctx->opTop = f->bp + 1; // restore the correct opstack frame!
|
||||||
STK(1) = a;
|
STK(1) = a;
|
||||||
@@ -609,13 +660,16 @@ static naRef run(struct Context* ctx)
|
|||||||
break;
|
break;
|
||||||
case OP_MARK: // save stack state (e.g. "setjmp")
|
case OP_MARK: // save stack state (e.g. "setjmp")
|
||||||
if(ctx->markTop >= MAX_MARK_DEPTH)
|
if(ctx->markTop >= MAX_MARK_DEPTH)
|
||||||
naRuntimeError(ctx, "mark stack overflow");
|
ERR(ctx, "mark stack overflow");
|
||||||
ctx->markStack[ctx->markTop++] = ctx->opTop;
|
ctx->markStack[ctx->markTop++] = ctx->opTop;
|
||||||
break;
|
break;
|
||||||
case OP_UNMARK: // pop stack state set by mark
|
case OP_UNMARK: // pop stack state set by mark
|
||||||
ctx->markTop--;
|
ctx->markTop--;
|
||||||
break;
|
break;
|
||||||
case OP_BREAK: // restore stack state (FOLLOW WITH JMP!)
|
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];
|
ctx->opTop = ctx->markStack[--ctx->markTop];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -636,48 +690,55 @@ void naSave(struct Context* ctx, naRef obj)
|
|||||||
naVec_append(globals->save, obj);
|
naVec_append(globals->save, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: handle ctx->callParent
|
|
||||||
int naStackDepth(struct Context* ctx)
|
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)
|
int naGetLine(struct Context* ctx, int frame)
|
||||||
{
|
{
|
||||||
struct Frame* f = &ctx->fStack[ctx->fTop-1-frame];
|
struct Frame* f;
|
||||||
naRef func = f->func;
|
frame = findFrame(ctx, &ctx, frame);
|
||||||
int ip = f->ip;
|
f = &ctx->fStack[frame];
|
||||||
if(IS_FUNC(func) && IS_CODE(func.ref.ptr.func->code)) {
|
if(IS_FUNC(f->func) && IS_CODE(PTR(f->func).func->code)) {
|
||||||
struct naCode* c = func.ref.ptr.func->code.ref.ptr.code;
|
struct naCode* c = PTR(PTR(f->func).func->code).code;
|
||||||
unsigned short* p = c->lineIps + c->nLines - 2;
|
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;
|
p -= 2;
|
||||||
return p[1];
|
return p[1];
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: handle ctx->callParent
|
|
||||||
naRef naGetSourceFile(struct Context* ctx, int frame)
|
naRef naGetSourceFile(struct Context* ctx, int frame)
|
||||||
{
|
{
|
||||||
naRef f = ctx->fStack[ctx->fTop-1-frame].func;
|
naRef f;
|
||||||
f = f.ref.ptr.func->code;
|
frame = findFrame(ctx, &ctx, frame);
|
||||||
return f.ref.ptr.code->srcFile;
|
f = ctx->fStack[frame].func;
|
||||||
|
f = PTR(f).func->code;
|
||||||
|
return PTR(f).code->srcFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* naGetError(struct Context* ctx)
|
char* naGetError(struct Context* ctx)
|
||||||
{
|
{
|
||||||
if(IS_STR(ctx->dieArg))
|
if(IS_STR(ctx->dieArg))
|
||||||
return (char*)ctx->dieArg.ref.ptr.str->data;
|
return (char*)PTR(ctx->dieArg).str->data;
|
||||||
return ctx->error;
|
return ctx->error[0] ? ctx->error : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naBindFunction(naContext ctx, naRef code, naRef closure)
|
naRef naBindFunction(naContext ctx, naRef code, naRef closure)
|
||||||
{
|
{
|
||||||
naRef func = naNewFunc(ctx, code);
|
naRef func = naNewFunc(ctx, code);
|
||||||
func.ref.ptr.func->namespace = closure;
|
PTR(func).func->namespace = closure;
|
||||||
func.ref.ptr.func->next = naNil();
|
PTR(func).func->next = naNil();
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,8 +746,8 @@ naRef naBindToContext(naContext ctx, naRef code)
|
|||||||
{
|
{
|
||||||
naRef func = naNewFunc(ctx, code);
|
naRef func = naNewFunc(ctx, code);
|
||||||
struct Frame* f = &ctx->fStack[ctx->fTop-1];
|
struct Frame* f = &ctx->fStack[ctx->fTop-1];
|
||||||
func.ref.ptr.func->namespace = f->locals;
|
PTR(func).func->namespace = f->locals;
|
||||||
func.ref.ptr.func->next = f->func;
|
PTR(func).func->next = f->func;
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,7 +756,7 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
naRef result;
|
naRef result;
|
||||||
if(!ctx->callParent) naModLock(ctx);
|
if(!ctx->callParent) naModLock();
|
||||||
|
|
||||||
// We might have to allocate objects, which can call the GC. But
|
// 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
|
// 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, obj);
|
||||||
naTempSave(ctx, locals);
|
naTempSave(ctx, locals);
|
||||||
|
|
||||||
if(IS_CCODE(func.ref.ptr.func->code)) {
|
// naRuntimeError() calls end up here:
|
||||||
naCFunction fp = func.ref.ptr.func->code.ref.ptr.ccode->fptr;
|
if(setjmp(ctx->jumpHandle)) {
|
||||||
result = (*fp)(ctx, obj, argc, args);
|
|
||||||
if(!ctx->callParent) naModUnlock(ctx);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IS_NIL(locals))
|
if(IS_NIL(locals))
|
||||||
locals = naNewHash(ctx);
|
locals = naNewHash(ctx);
|
||||||
if(!IS_FUNC(func))
|
if(!IS_FUNC(func)) {
|
||||||
func = naNewFunc(ctx, func); // bind bare code objects
|
func = naNewFunc(ctx, func);
|
||||||
|
PTR(func).func->namespace = locals;
|
||||||
|
}
|
||||||
if(!IS_NIL(obj))
|
if(!IS_NIL(obj))
|
||||||
naHash_set(locals, globals->meRef, obj);
|
naHash_set(locals, globals->meRef, obj);
|
||||||
|
|
||||||
ctx->dieArg = naNil();
|
|
||||||
|
|
||||||
ctx->opTop = ctx->markTop = 0;
|
ctx->opTop = ctx->markTop = 0;
|
||||||
ctx->fTop = 1;
|
ctx->fTop = 1;
|
||||||
ctx->fStack[0].func = func;
|
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].ip = 0;
|
||||||
ctx->fStack[0].bp = ctx->opTop;
|
ctx->fStack[0].bp = ctx->opTop;
|
||||||
|
|
||||||
setupArgs(ctx, ctx->fStack, args, argc);
|
if(args) 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
result = run(ctx);
|
result = run(ctx);
|
||||||
if(!ctx->callParent) naModUnlock(ctx);
|
if(!ctx->callParent) naModUnlock(ctx);
|
||||||
return result;
|
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
|
#define MAX_MARK_DEPTH 128
|
||||||
|
|
||||||
// Number of objects (per pool per thread) asked for using naGC_get().
|
// Number of objects (per pool per thread) asked for using naGC_get().
|
||||||
// Testing with fib.nas shows that this gives the best performance,
|
// The idea is that contexts can "cache" allocations to prevent thread
|
||||||
// without too much per-thread overhead.
|
// contention on the global pools. But in practice this interacts
|
||||||
#define OBJ_CACHE_SZ 128
|
// 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 {
|
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_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_JMP, OP_JMPLOOP, OP_JIFNOTPOP, OP_JIFEND, OP_FCALL, OP_MCALL,
|
||||||
OP_PUSHCONST, OP_PUSHONE, OP_PUSHZERO, OP_PUSHNIL, OP_POP,
|
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_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
|
||||||
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
|
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_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2, OP_INDEX, OP_BREAK2,
|
||||||
OP_INDEX
|
OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
@@ -69,6 +73,7 @@ struct Context {
|
|||||||
struct Frame fStack[MAX_RECURSION];
|
struct Frame fStack[MAX_RECURSION];
|
||||||
int fTop;
|
int fTop;
|
||||||
naRef opStack[MAX_STACK_DEPTH];
|
naRef opStack[MAX_STACK_DEPTH];
|
||||||
|
int opFrame; // like Frame::bp, but for C functions
|
||||||
int opTop;
|
int opTop;
|
||||||
int markStack[MAX_MARK_DEPTH];
|
int markStack[MAX_MARK_DEPTH];
|
||||||
int markTop;
|
int markTop;
|
||||||
@@ -86,7 +91,7 @@ struct Context {
|
|||||||
|
|
||||||
// Error handling
|
// Error handling
|
||||||
jmp_buf jumpHandle;
|
jmp_buf jumpHandle;
|
||||||
char* error;
|
char error[128];
|
||||||
naRef dieArg;
|
naRef dieArg;
|
||||||
|
|
||||||
// Sub-call lists
|
// Sub-call lists
|
||||||
@@ -96,6 +101,8 @@ struct Context {
|
|||||||
// Linked list pointers in globals
|
// Linked list pointers in globals
|
||||||
struct Context* nextFree;
|
struct Context* nextFree;
|
||||||
struct Context* nextAll;
|
struct Context* nextAll;
|
||||||
|
|
||||||
|
void* userData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define globals nasal_globals
|
#define globals nasal_globals
|
||||||
@@ -103,11 +110,13 @@ extern struct Globals* globals;
|
|||||||
|
|
||||||
// Threading low-level functions
|
// Threading low-level functions
|
||||||
void* naNewLock();
|
void* naNewLock();
|
||||||
|
void naFreeLock(void* lock);
|
||||||
void naLock(void* lock);
|
void naLock(void* lock);
|
||||||
void naUnlock(void* lock);
|
void naUnlock(void* lock);
|
||||||
void* naNewSem();
|
void* naNewSem();
|
||||||
|
void naFreeSem(void* sem);
|
||||||
void naSemDown(void* sem);
|
void naSemDown(void* sem);
|
||||||
void naSemUpAll(void* sem, int count);
|
void naSemUp(void* sem, int count);
|
||||||
|
|
||||||
void naCheckBottleneck();
|
void naCheckBottleneck();
|
||||||
|
|
||||||
|
|||||||
+29
-56
@@ -91,41 +91,6 @@ static int findConstantIndex(struct Parser* p, struct Token* t)
|
|||||||
return internConstant(p, c);
|
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)
|
static int genScalarConstant(struct Parser* p, struct Token* t)
|
||||||
{
|
{
|
||||||
// These opcodes are for special-case use in other constructs, but
|
// 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)
|
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"
|
return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
|
||||||
} else if(t->type == TOK_SYMBOL) {
|
} else if(t->type == TOK_SYMBOL) {
|
||||||
*cidx = genScalarConstant(p, t);
|
*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)
|
static int defArg(struct Parser* p, struct Token* t)
|
||||||
{
|
{
|
||||||
if(t->type == TOK_LPAR) return defArg(p, RIGHT(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);
|
return findConstantIndex(p, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,8 +267,6 @@ static void genFuncall(struct Parser* p, struct Token* t)
|
|||||||
genExpr(p, LEFT(t));
|
genExpr(p, LEFT(t));
|
||||||
}
|
}
|
||||||
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
|
if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
|
||||||
if(tailContext(t))
|
|
||||||
op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL;
|
|
||||||
emitImmediate(p, op, nargs);
|
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)
|
static void genShortCircuit(struct Parser* p, struct Token* t)
|
||||||
{
|
{
|
||||||
int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND);
|
int end;
|
||||||
genExpr(p, LEFT(t));
|
genExpr(p, LEFT(t));
|
||||||
if(isAnd) emit(p, OP_NOT);
|
end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
|
||||||
jumpNext = emitJump(p, OP_JIFNOT);
|
emit(p, OP_POP);
|
||||||
emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE);
|
|
||||||
jumpEnd = emitJump(p, OP_JMP);
|
|
||||||
fixJumpTarget(p, jumpNext);
|
|
||||||
genExpr(p, RIGHT(t));
|
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;
|
int jumpNext, jumpEnd;
|
||||||
genExpr(p, tif->children); // the test
|
genExpr(p, tif->children); // the test
|
||||||
jumpNext = emitJump(p, OP_JIFNOT);
|
jumpNext = emitJump(p, OP_JIFNOTPOP);
|
||||||
genExprList(p, tif->children->next->children); // the body
|
genExprList(p, tif->children->next->children); // the body
|
||||||
jumpEnd = emitJump(p, OP_JMP);
|
jumpEnd = emitJump(p, OP_JMP);
|
||||||
fixJumpTarget(p, jumpNext);
|
fixJumpTarget(p, jumpNext);
|
||||||
@@ -374,7 +343,7 @@ static void genQuestion(struct Parser* p, struct Token* t)
|
|||||||
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
|
if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
|
||||||
naParseError(p, "invalid ?: expression", t->line);
|
naParseError(p, "invalid ?: expression", t->line);
|
||||||
genExpr(p, LEFT(t)); // the test
|
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
|
genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
|
||||||
jumpEnd = emitJump(p, OP_JMP);
|
jumpEnd = emitJump(p, OP_JMP);
|
||||||
fixJumpTarget(p, jumpNext);
|
fixJumpTarget(p, jumpNext);
|
||||||
@@ -420,7 +389,7 @@ static void genForWhile(struct Parser* p, struct Token* init,
|
|||||||
pushLoop(p, label);
|
pushLoop(p, label);
|
||||||
loopTop = p->cg->codesz;
|
loopTop = p->cg->codesz;
|
||||||
genExpr(p, test);
|
genExpr(p, test);
|
||||||
jumpEnd = emitJump(p, OP_JIFNOT);
|
jumpEnd = emitJump(p, OP_JIFNOTPOP);
|
||||||
genLoop(p, body, update, label, loopTop, jumpEnd);
|
genLoop(p, body, update, label, loopTop, jumpEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,17 +449,19 @@ static void genForEach(struct Parser* p, struct Token* t)
|
|||||||
vec = RIGHT(h);
|
vec = RIGHT(h);
|
||||||
body = RIGHT(t)->children;
|
body = RIGHT(t)->children;
|
||||||
|
|
||||||
pushLoop(p, label);
|
|
||||||
genExpr(p, vec);
|
genExpr(p, vec);
|
||||||
emit(p, OP_PUSHZERO);
|
emit(p, OP_PUSHZERO);
|
||||||
|
pushLoop(p, label);
|
||||||
loopTop = p->cg->codesz;
|
loopTop = p->cg->codesz;
|
||||||
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
|
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);
|
assignOp = genLValue(p, elem, &dummy);
|
||||||
emit(p, OP_XCHG);
|
emit(p, OP_XCHG);
|
||||||
emit(p, assignOp);
|
emit(p, assignOp);
|
||||||
emit(p, OP_POP);
|
emit(p, OP_POP);
|
||||||
genLoop(p, body, 0, label, loopTop, jumpEnd);
|
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)
|
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;
|
bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
|
||||||
cp = p->cg->loops[p->cg->loopTop - levels].contIP;
|
cp = p->cg->loops[p->cg->loopTop - levels].contIP;
|
||||||
for(i=0; i<levels; i++)
|
for(i=0; i<levels; i++)
|
||||||
emit(p, OP_BREAK);
|
emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
|
||||||
if(t->type == TOK_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);
|
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)
|
static void genExpr(struct Parser* p, struct Token* t)
|
||||||
{
|
{
|
||||||
int i, dummy;
|
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)
|
if(t->line != p->cg->lastLine)
|
||||||
newLineEntry(p, t->line);
|
newLineEntry(p, t->line);
|
||||||
p->cg->lastLine = t->line;
|
p->cg->lastLine = t->line;
|
||||||
@@ -611,7 +584,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
case TOK_MINUS:
|
case TOK_MINUS:
|
||||||
if(BINARY(t)) {
|
if(BINARY(t)) {
|
||||||
genBinOp(OP_MINUS, p, t); // binary subtraction
|
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
|
RIGHT(t)->num *= -1; // Pre-negate constants
|
||||||
genScalarConstant(p, RIGHT(t));
|
genScalarConstant(p, RIGHT(t));
|
||||||
} else {
|
} else {
|
||||||
@@ -625,7 +598,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
break;
|
break;
|
||||||
case TOK_DOT:
|
case TOK_DOT:
|
||||||
genExpr(p, LEFT(t));
|
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);
|
naParseError(p, "object field not symbol", RIGHT(t)->line);
|
||||||
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
|
emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
|
||||||
break;
|
break;
|
||||||
@@ -656,7 +629,7 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
|
|
||||||
static void genExprList(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));
|
genExpr(p, LEFT(t));
|
||||||
if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
|
if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
|
||||||
emit(p, OP_POP);
|
emit(p, OP_POP);
|
||||||
@@ -690,7 +663,7 @@ naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
|
|||||||
|
|
||||||
// Now make a code object
|
// Now make a code object
|
||||||
codeObj = naNewCode(p->context);
|
codeObj = naNewCode(p->context);
|
||||||
code = codeObj.ref.ptr.code;
|
code = PTR(codeObj).code;
|
||||||
|
|
||||||
// Parse the argument list, if any
|
// Parse the argument list, if any
|
||||||
code->restArgSym = globals->argRef;
|
code->restArgSym = globals->argRef;
|
||||||
|
|||||||
+72
-16
@@ -3,30 +3,86 @@
|
|||||||
|
|
||||||
#include "nasal.h"
|
#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,
|
enum { T_STR, T_VEC, T_HASH, T_CODE, T_FUNC, T_CCODE, T_GHOST,
|
||||||
NUM_NASAL_TYPES }; // V. important that this come last!
|
NUM_NASAL_TYPES }; // V. important that this come last!
|
||||||
|
|
||||||
#define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG)
|
#define IS_NUM(r) (!IS_REF(r))
|
||||||
#define IS_NUM(r) ((r).ref.reftag != NASAL_REFTAG)
|
#define IS_OBJ(r) (IS_REF(r) && PTR(r).obj != 0)
|
||||||
#define IS_OBJ(r) (IS_REF((r)) && (r).ref.ptr.obj != 0)
|
#define IS_NIL(r) (IS_REF(r) && PTR(r).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_STR(r) (IS_OBJ(r) && PTR(r).obj->type == T_STR)
|
||||||
#define IS_NIL(r) (IS_REF((r)) && (r).ref.ptr.obj == 0)
|
#define IS_VEC(r) (IS_OBJ(r) && PTR(r).obj->type == T_VEC)
|
||||||
#define IS_STR(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_STR)
|
#define IS_HASH(r) (IS_OBJ(r) && PTR(r).obj->type == T_HASH)
|
||||||
#define IS_VEC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_VEC)
|
#define IS_CODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CODE)
|
||||||
#define IS_HASH(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_HASH)
|
#define IS_FUNC(r) (IS_OBJ(r) && PTR(r).obj->type == T_FUNC)
|
||||||
#define IS_CODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CODE)
|
#define IS_CCODE(r) (IS_OBJ(r) && PTR(r).obj->type == T_CCODE)
|
||||||
#define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC)
|
#define IS_GHOST(r) (IS_OBJ(r) && PTR(r).obj->type == T_GHOST)
|
||||||
#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_CONTAINER(r) (IS_VEC(r)||IS_HASH(r))
|
#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) \
|
#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
|
// 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
|
// 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".
|
// implementing objects to pack in 16 bits worth of data "for free".
|
||||||
#define GC_HEADER \
|
#define GC_HEADER \
|
||||||
|
|||||||
+27
-37
@@ -2,7 +2,7 @@
|
|||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "code.h"
|
#include "code.h"
|
||||||
|
|
||||||
#define MIN_BLOCK_SIZE 256
|
#define MIN_BLOCK_SIZE 32
|
||||||
|
|
||||||
static void reap(struct naPool* p);
|
static void reap(struct naPool* p);
|
||||||
static void mark(naRef r);
|
static void mark(naRef r);
|
||||||
@@ -27,7 +27,7 @@ static void marktemps(struct Context* c)
|
|||||||
int i;
|
int i;
|
||||||
naRef r = naNil();
|
naRef r = naNil();
|
||||||
for(i=0; i<c->ntemps; i++) {
|
for(i=0; i<c->ntemps; i++) {
|
||||||
r.ref.ptr.obj = c->temps[i];
|
SETPTR(r, c->temps[i]);
|
||||||
mark(r);
|
mark(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ static void bottleneck()
|
|||||||
if(g->waitCount >= g->nThreads - 1) {
|
if(g->waitCount >= g->nThreads - 1) {
|
||||||
freeDead();
|
freeDead();
|
||||||
if(g->needGC) garbageCollect();
|
if(g->needGC) garbageCollect();
|
||||||
if(g->waitCount) naSemUpAll(g->sem, g->waitCount);
|
if(g->waitCount) naSemUp(g->sem, g->waitCount);
|
||||||
g->bottleneck = 0;
|
g->bottleneck = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,34 +130,21 @@ static void naCode_gcclean(struct naCode* o)
|
|||||||
|
|
||||||
static void naGhost_gcclean(struct naGhost* g)
|
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;
|
g->ptr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeelem(struct naPool* p, struct naObj* o)
|
static void freeelem(struct naPool* p, struct naObj* o)
|
||||||
{
|
{
|
||||||
// Free any intrinsic (i.e. non-garbage collected) storage the
|
// Clean up any intrinsic storage the object might have...
|
||||||
// object might have
|
|
||||||
switch(p->type) {
|
switch(p->type) {
|
||||||
case T_STR:
|
case T_STR: naStr_gcclean ((struct naStr*) o); break;
|
||||||
naStr_gcclean((struct naStr*)o);
|
case T_VEC: naVec_gcclean ((struct naVec*) o); break;
|
||||||
break;
|
case T_HASH: naHash_gcclean ((struct naHash*) o); break;
|
||||||
case T_VEC:
|
case T_CODE: naCode_gcclean ((struct naCode*) o); break;
|
||||||
naVec_gcclean((struct naVec*)o);
|
case T_GHOST: naGhost_gcclean((struct naGhost*)o); break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
p->free[p->nfree++] = o; // ...and add it to the free list
|
||||||
// And add it to the free list
|
|
||||||
p->free[p->nfree++] = o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void newBlock(struct naPool* p, int need)
|
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)
|
static void markvec(naRef r)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct VecRec* vr = r.ref.ptr.vec->rec;
|
struct VecRec* vr = PTR(r).vec->rec;
|
||||||
if(!vr) return;
|
if(!vr) return;
|
||||||
for(i=0; i<vr->size; i++)
|
for(i=0; i<vr->size; i++)
|
||||||
mark(vr->array[i]);
|
mark(vr->array[i]);
|
||||||
@@ -236,7 +223,7 @@ static void markvec(naRef r)
|
|||||||
static void markhash(naRef r)
|
static void markhash(naRef r)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct HashRec* hr = r.ref.ptr.hash->rec;
|
struct HashRec* hr = PTR(r).hash->rec;
|
||||||
if(!hr) return;
|
if(!hr) return;
|
||||||
for(i=0; i < (1<<hr->lgalloced); i++) {
|
for(i=0; i < (1<<hr->lgalloced); i++) {
|
||||||
struct HashNode* hn = hr->table[i];
|
struct HashNode* hn = hr->table[i];
|
||||||
@@ -257,22 +244,22 @@ static void mark(naRef r)
|
|||||||
if(IS_NUM(r) || IS_NIL(r))
|
if(IS_NUM(r) || IS_NIL(r))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(r.ref.ptr.obj->mark == 1)
|
if(PTR(r).obj->mark == 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
r.ref.ptr.obj->mark = 1;
|
PTR(r).obj->mark = 1;
|
||||||
switch(r.ref.ptr.obj->type) {
|
switch(PTR(r).obj->type) {
|
||||||
case T_VEC: markvec(r); break;
|
case T_VEC: markvec(r); break;
|
||||||
case T_HASH: markhash(r); break;
|
case T_HASH: markhash(r); break;
|
||||||
case T_CODE:
|
case T_CODE:
|
||||||
mark(r.ref.ptr.code->srcFile);
|
mark(PTR(r).code->srcFile);
|
||||||
for(i=0; i<r.ref.ptr.code->nConstants; i++)
|
for(i=0; i<PTR(r).code->nConstants; i++)
|
||||||
mark(r.ref.ptr.code->constants[i]);
|
mark(PTR(r).code->constants[i]);
|
||||||
break;
|
break;
|
||||||
case T_FUNC:
|
case T_FUNC:
|
||||||
mark(r.ref.ptr.func->code);
|
mark(PTR(r).func->code);
|
||||||
mark(r.ref.ptr.func->namespace);
|
mark(PTR(r).func->namespace);
|
||||||
mark(r.ref.ptr.func->next);
|
mark(PTR(r).func->next);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,7 +270,6 @@ static void reap(struct naPool* p)
|
|||||||
{
|
{
|
||||||
struct Block* b;
|
struct Block* b;
|
||||||
int elem, freesz, total = poolsize(p);
|
int elem, freesz, total = poolsize(p);
|
||||||
p->nfree = 0;
|
|
||||||
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
|
freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total;
|
||||||
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
|
freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ);
|
||||||
if(p->freesz < freesz) {
|
if(p->freesz < freesz) {
|
||||||
@@ -292,6 +278,9 @@ static void reap(struct naPool* p)
|
|||||||
p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz);
|
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(b = p->blocks; b; b = b->next)
|
||||||
for(elem=0; elem < b->size; elem++) {
|
for(elem=0; elem < b->size; elem++) {
|
||||||
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
|
struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz);
|
||||||
@@ -300,6 +289,8 @@ static void reap(struct naPool* p)
|
|||||||
o->mark = 0;
|
o->mark = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->freetop = p->nfree;
|
||||||
|
|
||||||
// allocs of this type until the next collection
|
// allocs of this type until the next collection
|
||||||
globals->allocCount += total/2;
|
globals->allocCount += total/2;
|
||||||
|
|
||||||
@@ -312,7 +303,6 @@ static void reap(struct naPool* p)
|
|||||||
if(need > 0)
|
if(need > 0)
|
||||||
newBlock(p, need);
|
newBlock(p, need);
|
||||||
}
|
}
|
||||||
p->freetop = p->nfree;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does the swap, returning the old value
|
// Does the swap, returning the old value
|
||||||
|
|||||||
+35
-30
@@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
#define MIN_HASH_SIZE 4
|
#define MIN_HASH_SIZE 4
|
||||||
|
|
||||||
#define EQUAL(a, b) (((a).ref.reftag == (b).ref.reftag \
|
#define EQUAL(a, b) (IDENTICAL(a, b) || naEqual(a, b))
|
||||||
&& (a).ref.ptr.obj == (b).ref.ptr.obj) \
|
|
||||||
|| naEqual(a, b))
|
|
||||||
|
|
||||||
#define HASH_MAGIC 2654435769u
|
#define HASH_MAGIC 2654435769u
|
||||||
|
|
||||||
@@ -28,15 +26,15 @@ static unsigned int hashcode(naRef r)
|
|||||||
// 2*sizeof(int).
|
// 2*sizeof(int).
|
||||||
unsigned int* p = (unsigned int*)&(r.num);
|
unsigned int* p = (unsigned int*)&(r.num);
|
||||||
return p[0] ^ p[1];
|
return p[0] ^ p[1];
|
||||||
} else if(r.ref.ptr.str->hashcode) {
|
} else if(PTR(r).str->hashcode) {
|
||||||
return r.ref.ptr.str->hashcode;
|
return PTR(r).str->hashcode;
|
||||||
} else {
|
} else {
|
||||||
// This is Daniel Bernstein's djb2 hash function that I found
|
// This is Daniel Bernstein's djb2 hash function that I found
|
||||||
// on the web somewhere. It appears to work pretty well.
|
// on the web somewhere. It appears to work pretty well.
|
||||||
unsigned int i, hash = 5831;
|
unsigned int i, hash = 5831;
|
||||||
for(i=0; i<r.ref.ptr.str->len; i++)
|
for(i=0; i<PTR(r).str->len; i++)
|
||||||
hash = (hash * 33) ^ r.ref.ptr.str->data[i];
|
hash = (hash * 33) ^ PTR(r).str->data[i];
|
||||||
r.ref.ptr.str->hashcode = hash;
|
PTR(r).str->hashcode = hash;
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +47,7 @@ static unsigned int hashcolumn(struct HashRec* h, naRef key)
|
|||||||
return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced);
|
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;
|
struct HashRec *h, *h0 = hash->rec;
|
||||||
int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE;
|
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);
|
int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
|
||||||
struct HashNode* hn = h->table[col];
|
struct HashNode* hn = h->table[col];
|
||||||
while(hn) {
|
while(hn) {
|
||||||
if(hn->key.ref.ptr.str == sym) {
|
if(PTR(hn->key).str == sym) {
|
||||||
*out = hn->val;
|
*out = hn->val;
|
||||||
return 1;
|
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)
|
static struct HashNode* find(struct naHash* hash, naRef key)
|
||||||
{
|
{
|
||||||
struct HashRec* h = hash->rec;
|
struct HashRec* h = hash->rec;
|
||||||
if(h) {
|
struct HashNode* hn;
|
||||||
struct HashNode* hn = h->table[hashcolumn(h, key)];
|
if(!h) return 0;
|
||||||
while(hn) {
|
for(hn = h->table[hashcolumn(h, key)]; hn; hn = hn->next)
|
||||||
if(EQUAL(key, hn->key))
|
if(EQUAL(key, hn->key))
|
||||||
return hn;
|
return hn;
|
||||||
hn = hn->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a temporary string on the stack
|
// 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->len = 0;
|
||||||
|
str->type = T_STR;
|
||||||
str->data = (unsigned char*)key;
|
str->data = (unsigned char*)key;
|
||||||
|
str->hashcode = 0;
|
||||||
while(key[str->len]) str->len++;
|
while(key[str->len]) str->len++;
|
||||||
*out = naNil();
|
*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)
|
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)
|
int naHash_get(naRef hash, naRef key, naRef* out)
|
||||||
{
|
{
|
||||||
if(IS_HASH(hash)) {
|
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; }
|
if(n) { *out = n->val; return 1; }
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -155,7 +160,7 @@ int naHash_get(naRef hash, naRef key, naRef* out)
|
|||||||
int naHash_tryset(naRef hash, naRef key, naRef val)
|
int naHash_tryset(naRef hash, naRef key, naRef val)
|
||||||
{
|
{
|
||||||
if(IS_HASH(hash)) {
|
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;
|
if(n) n->val = val;
|
||||||
return n != 0;
|
return n != 0;
|
||||||
}
|
}
|
||||||
@@ -171,8 +176,8 @@ void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
|
|||||||
int col;
|
int col;
|
||||||
struct HashRec* h = hash->rec;
|
struct HashRec* h = hash->rec;
|
||||||
while(!h || h->size >= 1<<h->lgalloced)
|
while(!h || h->size >= 1<<h->lgalloced)
|
||||||
h = hashrealloc(hash);
|
h = resize(hash);
|
||||||
col = (HASH_MAGIC * sym->ref.ptr.str->hashcode) >> (32 - h->lgalloced);
|
col = (HASH_MAGIC * PTR(*sym).str->hashcode) >> (32 - h->lgalloced);
|
||||||
INSERT(h, *sym, *val, col);
|
INSERT(h, *sym, *val, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,10 +200,10 @@ void naHash_set(naRef hash, naRef key, naRef val)
|
|||||||
struct HashRec* h;
|
struct HashRec* h;
|
||||||
struct HashNode* n;
|
struct HashNode* n;
|
||||||
if(!IS_HASH(hash)) return;
|
if(!IS_HASH(hash)) return;
|
||||||
if((n = find(hash.ref.ptr.hash, key))) { n->val = val; return; }
|
if((n = find(PTR(hash).hash, key))) { n->val = val; return; }
|
||||||
h = hash.ref.ptr.hash->rec;
|
h = PTR(hash).hash->rec;
|
||||||
while(!h || h->size >= 1<<h->lgalloced)
|
while(!h || h->size >= 1<<h->lgalloced)
|
||||||
h = hashrealloc(hash.ref.ptr.hash);
|
h = resize(PTR(hash).hash);
|
||||||
col = hashcolumn(h, key);
|
col = hashcolumn(h, key);
|
||||||
INSERT(h, key, val, hashcolumn(h, key));
|
INSERT(h, key, val, hashcolumn(h, key));
|
||||||
chkcycle(h->table[col], h->size - h->dels);
|
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)
|
void naHash_delete(naRef hash, naRef key)
|
||||||
{
|
{
|
||||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
struct HashRec* h = PTR(hash).hash->rec;
|
||||||
int col;
|
int col;
|
||||||
struct HashNode *last=0, *hn;
|
struct HashNode *last=0, *hn;
|
||||||
if(!IS_HASH(hash) || !h) return;
|
if(!IS_HASH(hash) || !h) return;
|
||||||
@@ -227,7 +232,7 @@ void naHash_delete(naRef hash, naRef key)
|
|||||||
void naHash_keys(naRef dst, naRef hash)
|
void naHash_keys(naRef dst, naRef hash)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct HashRec* h = hash.ref.ptr.hash->rec;
|
struct HashRec* h = PTR(hash).hash->rec;
|
||||||
if(!IS_HASH(hash) || !h) return;
|
if(!IS_HASH(hash) || !h) return;
|
||||||
for(i=0; i<(1<<h->lgalloced); i++) {
|
for(i=0; i<(1<<h->lgalloced); i++) {
|
||||||
struct HashNode* hn = h->table[i];
|
struct HashNode* hn = h->table[i];
|
||||||
@@ -240,7 +245,7 @@ void naHash_keys(naRef dst, naRef hash)
|
|||||||
|
|
||||||
int naHash_size(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;
|
if(!IS_HASH(hash) || !h) return 0;
|
||||||
return h->size - h->dels;
|
return h->size - h->dels;
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-29
@@ -11,7 +11,7 @@ naGhostType naIOGhostType = { ghostDestroy };
|
|||||||
|
|
||||||
static struct naIOGhost* ioghost(naRef r)
|
static struct naIOGhost* ioghost(naRef r)
|
||||||
{
|
{
|
||||||
if(naGhost_type(r) == &naIOGhostType)
|
if(naGhost_type(r) == &naIOGhostType && IOGHOST(r)->handle)
|
||||||
return naGhost_ptr(r);
|
return naGhost_ptr(r);
|
||||||
return 0;
|
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();
|
naRef len = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||||
if(!g || !MUTABLE(str) || !IS_NUM(len))
|
if(!g || !MUTABLE(str) || !IS_NUM(len))
|
||||||
naRuntimeError(c, "bad argument to read()");
|
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");
|
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));
|
(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();
|
naRef str = argc > 1 ? args[1] : naNil();
|
||||||
if(!g || !IS_STR(str))
|
if(!g || !IS_STR(str))
|
||||||
naRuntimeError(c, "bad argument to write()");
|
naRuntimeError(c, "bad argument to write()");
|
||||||
return naNum(g->type->write(c, g->handle, (char*)str.ref.ptr.str->data,
|
return naNum(g->type->write(c, g->handle, (char*)PTR(str).str->data,
|
||||||
str.ref.ptr.str->len));
|
PTR(str).str->len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_seek(naContext c, naRef me, int argc, naRef* args)
|
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)
|
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,
|
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 file = argc > 0 ? naStringValue(c, args[0]) : naNil();
|
||||||
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
|
naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
|
||||||
if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
|
if(!IS_STR(file)) naRuntimeError(c, "bad argument to open()");
|
||||||
f = fopen((char*)file.ref.ptr.str->data,
|
f = fopen((char*)PTR(file).str->data,
|
||||||
IS_STR(mode) ? (const char*)mode.ref.ptr.str->data : "r");
|
IS_STR(mode) ? (const char*)PTR(mode).str->data : "rb");
|
||||||
if(!f) naRuntimeError(c, strerror(errno));
|
if(!f) naRuntimeError(c, strerror(errno));
|
||||||
return naIOGhost(c, f);
|
return naIOGhost(c, f);
|
||||||
}
|
}
|
||||||
@@ -169,7 +170,8 @@ static naRef f_readln(naContext ctx, naRef me, int argc, naRef* args)
|
|||||||
if(c == '\r') {
|
if(c == '\r') {
|
||||||
char c2 = getcguard(ctx, g->handle, buf);
|
char c2 = getcguard(ctx, g->handle, buf);
|
||||||
if(c2 != EOF && c2 != '\n')
|
if(c2 != EOF && c2 != '\n')
|
||||||
ungetc(c2, g->handle);
|
if(EOF == ungetc(c2, g->handle))
|
||||||
|
break;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buf[i++] = c;
|
buf[i++] = c;
|
||||||
@@ -186,7 +188,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
|
|||||||
struct stat s;
|
struct stat s;
|
||||||
naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
|
naRef result, path = argc > 0 ? naStringValue(ctx, args[0]) : naNil();
|
||||||
if(!IS_STR(path)) naRuntimeError(ctx, "bad argument to stat()");
|
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();
|
if(errno == ENOENT) return naNil();
|
||||||
naRuntimeError(ctx, strerror(errno));
|
naRuntimeError(ctx, strerror(errno));
|
||||||
}
|
}
|
||||||
@@ -199,7 +201,7 @@ static naRef f_stat(naContext ctx, naRef me, int argc, naRef* args)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct func { char* name; naCFunction func; } funcs[] = {
|
static naCFuncItem funcs[] = {
|
||||||
{ "close", f_close },
|
{ "close", f_close },
|
||||||
{ "read", f_read },
|
{ "read", f_read },
|
||||||
{ "write", f_write },
|
{ "write", f_write },
|
||||||
@@ -208,26 +210,17 @@ static struct func { char* name; naCFunction func; } funcs[] = {
|
|||||||
{ "open", f_open },
|
{ "open", f_open },
|
||||||
{ "readln", f_readln },
|
{ "readln", f_readln },
|
||||||
{ "stat", f_stat },
|
{ "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));
|
naRef ns = naGenLib(c, funcs);
|
||||||
naHash_set(hash, naInternSymbol(name), val);
|
naAddSym(c, ns, "SEEK_SET", naNum(SEEK_SET));
|
||||||
}
|
naAddSym(c, ns, "SEEK_CUR", naNum(SEEK_CUR));
|
||||||
|
naAddSym(c, ns, "SEEK_END", naNum(SEEK_END));
|
||||||
naRef naIOLib(naContext c)
|
naAddSym(c, ns, "stdin", naIOGhost(c, stdin));
|
||||||
{
|
naAddSym(c, ns, "stdout", naIOGhost(c, stdout));
|
||||||
naRef ns = naNewHash(c);
|
naAddSym(c, ns, "stderr", naIOGhost(c, stderr));
|
||||||
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));
|
|
||||||
return ns;
|
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,
|
static void newToken(struct Parser* p, int pos, int type,
|
||||||
char* str, int slen, double num)
|
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 = naParseAlloc(p, sizeof(struct Token));
|
||||||
tok->type = type;
|
tok->type = type;
|
||||||
@@ -119,17 +132,18 @@ static void newToken(struct Parser* p, int pos, int type,
|
|||||||
tok->num = num;
|
tok->num = num;
|
||||||
tok->parent = &p->tree;
|
tok->parent = &p->tree;
|
||||||
tok->next = 0;
|
tok->next = 0;
|
||||||
tok->prev = p->tree.lastChild;
|
tok->prev = last;
|
||||||
tok->children = 0;
|
tok->children = 0;
|
||||||
tok->lastChild = 0;
|
tok->lastChild = 0;
|
||||||
|
|
||||||
// Context sensitivity hack: a "-" following a binary operator of
|
// Context sensitivity hack: a "-" following a binary operator of
|
||||||
// higher precedence (MUL and DIV, basically) must be a unary
|
// equal or higher precedence must be a unary negation. Needed to
|
||||||
// negation. Needed to get precedence right in the parser for
|
// get precedence right in the parser for expressiong like "a * -2"
|
||||||
// expressiong like "a * -2"
|
if(type == TOK_MINUS && tok->prev) {
|
||||||
if(type == TOK_MINUS && tok->prev)
|
int pt = tok->prev->type;
|
||||||
if(tok->prev->type == TOK_MUL || tok->prev->type == TOK_DIV)
|
if(pt==TOK_PLUS||pt==TOK_MINUS||pt==TOK_CAT||pt==TOK_MUL||pt==TOK_DIV)
|
||||||
tok->type = type = TOK_NEG;
|
tok->type = type = TOK_NEG;
|
||||||
|
}
|
||||||
|
|
||||||
if(!p->tree.children) p->tree.children = tok;
|
if(!p->tree.children) p->tree.children = tok;
|
||||||
if(p->tree.lastChild) p->tree.lastChild->next = 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 'n': *cOut = '\n'; break;
|
||||||
case 't': *cOut = '\t'; break;
|
case 't': *cOut = '\t'; break;
|
||||||
case '\\': *cOut = '\\'; break;
|
case '\\': *cOut = '\\'; break;
|
||||||
|
case '`': *cOut = '`'; break;
|
||||||
case 'x':
|
case 'x':
|
||||||
if(len < 4) error(p, "unterminated string", index);
|
if(len < 4) error(p, "unterminated string", index);
|
||||||
*cOut = (char)((hexc(buf[2], p, index)<<4) | hexc(buf[3], p, 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)
|
static void charLiteral(struct Parser* p, int index, char* s, int len)
|
||||||
{
|
{
|
||||||
if(len != 1) error(p, "character constant not single character", index);
|
int n, c;
|
||||||
newToken(p, index, TOK_LITERAL, 0, 0, *s);
|
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
|
// Read in a string literal
|
||||||
@@ -317,6 +333,7 @@ static int tryLexemes(struct Parser* p, int index, int* lexemeOut)
|
|||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ISNUM(c) ((c) >= '0' && (c) <= '9')
|
||||||
void naLex(struct Parser* p)
|
void naLex(struct Parser* p)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -338,7 +355,8 @@ void naLex(struct Parser* p)
|
|||||||
i = lexStringLiteral(p, i, c);
|
i = lexStringLiteral(p, i, c);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
else handled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+232
-145
@@ -5,6 +5,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER // sigh...
|
#ifdef _MSC_VER // sigh...
|
||||||
|
#define snprintf _snprintf
|
||||||
#define vsnprintf _vsnprintf
|
#define vsnprintf _vsnprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -14,9 +15,14 @@
|
|||||||
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
|
#define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
|
||||||
#define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
|
#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(naIsString(args[0])) return naNum(naStr_len(args[0]));
|
||||||
if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
|
if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
|
||||||
if(naIsHash(args[0])) return naNum(naHash_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();
|
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];
|
naRef v, h = argc > 0 ? args[0] : naNil();
|
||||||
if(!naIsHash(h)) return naNil();
|
if(!naIsHash(h)) ARGERR();
|
||||||
v = naNewVector(c);
|
v = naNewVector(c);
|
||||||
naHash_keys(v, h);
|
naHash_keys(v, h);
|
||||||
return v;
|
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;
|
int i;
|
||||||
if(argc < 2) return naNil();
|
if(argc < 2 || !naIsVector(args[0])) ARGERR();
|
||||||
if(!naIsVector(args[0])) return naNil();
|
|
||||||
for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
|
for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
|
||||||
return args[0];
|
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]);
|
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 || !naIsVector(args[0])) ARGERR();
|
||||||
if(argc < 2) return naNil();
|
naVec_setsize(args[0], (int)naNumValue(args[1]).num);
|
||||||
sz = (int)naNumValue(args[1]).num;
|
|
||||||
if(!naIsVector(args[0])) return naNil();
|
|
||||||
naVec_setsize(args[0], sz);
|
|
||||||
return args[0];
|
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;
|
int i;
|
||||||
naRef nlen, result, v = args[0];
|
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();
|
nlen = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||||
if(!naIsNil(nlen))
|
if(!naIsNil(nlen))
|
||||||
len = (int)nlen.num;
|
len = (int)nlen.num;
|
||||||
if(!naIsVector(v) || start < 0 || start >= naVec_size(v) || len < 0)
|
if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
|
||||||
return naNil();
|
ARGERR();
|
||||||
if(naIsNil(nlen) || len > naVec_size(v) - start)
|
if(naIsNil(nlen) || len > naVec_size(v) - start)
|
||||||
len = naVec_size(v) - start;
|
len = naVec_size(v) - start;
|
||||||
result = naNewVector(c);
|
result = naNewVector(c);
|
||||||
@@ -78,13 +80,14 @@ static naRef subvec(naContext c, naRef me, int argc, naRef* args)
|
|||||||
return result;
|
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]);
|
if(argc < 2 || !naIsHash(args[0])) ARGERR();
|
||||||
return naNil();
|
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) {
|
if(argc > 0) {
|
||||||
naRef n = naNumValue(args[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);
|
if(n.num < 0) n.num = -floor(-n.num);
|
||||||
else n.num = floor(n.num);
|
else n.num = floor(n.num);
|
||||||
return n;
|
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();
|
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();
|
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;
|
char *a, *b;
|
||||||
int i, alen, blen;
|
int i, alen, blen;
|
||||||
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
|
if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
|
||||||
naRuntimeError(c, "bad argument to cmp");
|
ARGERR();
|
||||||
a = naStr_data(args[0]);
|
a = naStr_data(args[0]);
|
||||||
alen = naStr_len(args[0]);
|
alen = naStr_len(args[0]);
|
||||||
b = naStr_data(args[1]);
|
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));
|
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();
|
int start, len, srclen;
|
||||||
naRef startR = argc > 1 ? naNumValue(args[1]) : naNil();
|
naRef src = argc > 0 ? args[0] : naNil();
|
||||||
naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil();
|
naRef startr = argc > 1 ? naNumValue(args[1]) : naNil();
|
||||||
int start, len;
|
naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil();
|
||||||
if(!naIsString(src)) return naNil();
|
if(!naIsString(src)) ARGERR();
|
||||||
if(naIsNil(startR)) return naNil();
|
if(naIsNil(startr) || !naIsNum(startr)) ARGERR();
|
||||||
start = (int)startR.num;
|
if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR();
|
||||||
if(naIsNil(lenR)) {
|
srclen = naStr_len(src);
|
||||||
len = naStr_len(src) - start;
|
start = (int)startr.num;
|
||||||
if(len < 0) return naNil();
|
len = naIsNum(lenr) ? (int)lenr.num : (srclen - start);
|
||||||
} else {
|
if(start < 0) start += srclen;
|
||||||
lenR = naNumValue(lenR);
|
if(start < 0) start = len = 0;
|
||||||
if(naIsNil(lenR)) return naNil();
|
if(start >= srclen) start = len = 0;
|
||||||
len = (int)lenR.num;
|
if(len < 0) len = 0;
|
||||||
}
|
if(len > srclen - start) len = srclen - start;
|
||||||
return naStr_substr(naNewString(c), src, start, len);
|
return naStr_substr(naNewString(c), src, start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
|
static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
|
||||||
{
|
{
|
||||||
char chr[1];
|
char chr[1];
|
||||||
naRef cr = argc ? naNumValue(args[0]) : naNil();
|
naRef cr = argc > 0 ? naNumValue(args[0]) : naNil();
|
||||||
if(IS_NIL(cr)) naRuntimeError(c, "chr argument not string");
|
if(IS_NIL(cr)) ARGERR();
|
||||||
chr[0] = (char)cr.num;
|
chr[0] = (char)cr.num;
|
||||||
return NEWSTR(c, chr, 1);
|
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 hash = argc > 0 ? args[0] : naNil();
|
||||||
naRef key = argc > 1 ? args[1] : 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();
|
if(!naIsHash(hash)) return naNil();
|
||||||
return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
|
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();
|
naRef r = argc > 0 ? args[0] : naNil();
|
||||||
char* t = "unknown";
|
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(naIsHash(r)) t = "hash";
|
||||||
else if(naIsFunc(r)) t = "func";
|
else if(naIsFunc(r)) t = "func";
|
||||||
else if(naIsGhost(r)) t = "ghost";
|
else if(naIsGhost(r)) t = "ghost";
|
||||||
r = NEWCSTR(c, t);
|
return NEWCSTR(c, t);
|
||||||
return r;
|
}
|
||||||
|
|
||||||
|
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)
|
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;
|
int errLine;
|
||||||
naRef script, code, fname;
|
naRef script, code, fname;
|
||||||
script = argc > 0 ? args[0] : naNil();
|
script = argc > 0 ? args[0] : naNil();
|
||||||
if(!naIsString(script)) return naNil();
|
fname = argc > 1 ? args[1] : NEWCSTR(c, "<compile>");
|
||||||
fname = NEWCSTR(c, "<compile>");
|
if(!naIsString(script) || !naIsString(fname)) return naNil();
|
||||||
code = naParseCode(c, fname, 1,
|
code = naParseCode(c, fname, 1,
|
||||||
naStr_data(script), naStr_len(script), &errLine);
|
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);
|
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)
|
static naRef f_call(naContext c, naRef me, int argc, naRef* args)
|
||||||
{
|
{
|
||||||
naContext subc;
|
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(callme)) callme = naNil();
|
||||||
if(!IS_HASH(callns)) callns = naNil();
|
if(!IS_HASH(callns)) callns = naNil();
|
||||||
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
|
if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
|
||||||
naRuntimeError(c, "bad argument to call()");
|
ARGERR();
|
||||||
subc = naNewContext();
|
|
||||||
subc->callParent = c;
|
subc = naSubContext(c);
|
||||||
c->callChild = subc;
|
vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
|
||||||
vr = IS_NIL(callargs) ? 0 : callargs.ref.ptr.vec->rec;
|
|
||||||
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
|
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
|
||||||
callme, callns);
|
callme, callns);
|
||||||
c->callChild = 0;
|
if(!naGetError(subc)) {
|
||||||
if(argc > 2 && IS_VEC(args[argc-1])) {
|
naFreeContext(subc);
|
||||||
if(!IS_NIL(subc->dieArg)) naVec_append(args[argc-1], subc->dieArg);
|
return result;
|
||||||
else if(naGetError(subc))
|
|
||||||
naVec_append(args[argc-1], NEWCSTR(subc, naGetError(subc)));
|
|
||||||
}
|
}
|
||||||
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)
|
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__");
|
naRuntimeError(c, "__die__");
|
||||||
return naNil(); // never executes
|
return naNil(); // never executes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper around vsnprintf, iteratively increasing the buffer size
|
// Wrapper around vsnprintf, iteratively increasing the buffer size
|
||||||
// until it fits. Returned buffer should be freed by the caller.
|
// until it fits. Returned buffer should be freed by the caller.
|
||||||
char* dosprintf(char* f, ...)
|
static char* dosprintf(char* f, ...)
|
||||||
{
|
{
|
||||||
char* buf;
|
char* buf;
|
||||||
va_list va;
|
va_list va;
|
||||||
@@ -251,7 +293,7 @@ char* dosprintf(char* f, ...)
|
|||||||
// all of ANSI C's syntax except for the "length modifier" feature.
|
// all of ANSI C's syntax except for the "length modifier" feature.
|
||||||
// Note: this does not validate the format character returned in
|
// Note: this does not validate the format character returned in
|
||||||
// "type". That is the caller's job.
|
// "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
|
// Skip to the start of the format string
|
||||||
while(*f && *f != '%') f++;
|
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(p1 = *out + 1; p1 < f; p1++)
|
||||||
for(p2 = p1+1; p2 < f; p2++)
|
for(p2 = p1+1; p2 < f; p2++)
|
||||||
if(*p1 == *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++;
|
while(*f && *f >= '0' && *f <= '9') f++;
|
||||||
if(*f && *f == '.') f++;
|
if(*f && *f == '.') f++;
|
||||||
while(*f && *f >= '0' && *f <= '9') f++;
|
while(*f && *f >= '0' && *f <= '9') f++;
|
||||||
if(!*f) naRuntimeError(ctx, "invalid format string");
|
if(!*f) naRuntimeError(c, "invalid format string");
|
||||||
|
|
||||||
*type = *f++;
|
*type = *f++;
|
||||||
*len = f - *out;
|
*len = f - *out;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ERR(m) naRuntimeError(ctx, m)
|
#define ERR(m) naRuntimeError(c, m)
|
||||||
#define APPEND(r) result = naStr_concat(naNewString(ctx), result, r)
|
#define APPEND(r) result = naStr_concat(naNewString(c), result, r)
|
||||||
static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
|
static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
|
||||||
{
|
{
|
||||||
char t, nultmp, *fstr, *next, *fout=0, *s;
|
char t, nultmp, *fstr, *next, *fout=0, *s;
|
||||||
int flen, argn=1;
|
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");
|
if(argc < 1) ERR("not enough arguments to sprintf()");
|
||||||
format = naStringValue(ctx, argc > 0 ? args[0] : naNil());
|
format = naStringValue(c, argc > 0 ? args[0] : naNil());
|
||||||
if(naIsNil(format)) ERR("bad format string in sprintf");
|
if(naIsNil(format)) ERR("bad format string in sprintf()");
|
||||||
s = naStr_data(format);
|
s = naStr_data(format);
|
||||||
|
|
||||||
while((next = nextFormat(ctx, s, &fstr, &flen, &t))) {
|
while((next = nextFormat(c, s, &fstr, &flen, &t))) {
|
||||||
APPEND(NEWSTR(ctx, s, fstr-s)); // stuff before the format string
|
APPEND(NEWSTR(c, s, fstr-s)); // stuff before the format string
|
||||||
if(flen == 2 && fstr[1] == '%') {
|
if(flen == 2 && fstr[1] == '%') {
|
||||||
APPEND(NEWSTR(ctx, "%", 1));
|
APPEND(NEWSTR(c, "%", 1));
|
||||||
s = next;
|
s = next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(argn >= argc) ERR("not enough arguments to sprintf");
|
if(argn >= argc) ERR("not enough arguments to sprintf()");
|
||||||
arg = args[argn++];
|
arg = args[argn++];
|
||||||
nultmp = fstr[flen]; // sneaky nul termination...
|
nultmp = fstr[flen]; // sneaky nul termination...
|
||||||
fstr[flen] = 0;
|
fstr[flen] = 0;
|
||||||
if(t == 's') {
|
if(t == 's') {
|
||||||
arg = naStringValue(ctx, arg);
|
arg = naStringValue(c, arg);
|
||||||
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
|
if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
|
||||||
else fout = dosprintf(fstr, naStr_data(arg));
|
else fout = dosprintf(fstr, naStr_data(arg));
|
||||||
} else {
|
} else {
|
||||||
@@ -320,44 +362,42 @@ static naRef f_sprintf(naContext ctx, naRef me, int argc, naRef* args)
|
|||||||
ERR("invalid sprintf format type");
|
ERR("invalid sprintf format type");
|
||||||
}
|
}
|
||||||
fstr[flen] = nultmp;
|
fstr[flen] = nultmp;
|
||||||
APPEND(NEWSTR(ctx, fout, strlen(fout)));
|
APPEND(NEWSTR(c, fout, strlen(fout)));
|
||||||
naFree(fout);
|
naFree(fout);
|
||||||
s = next;
|
s = next;
|
||||||
}
|
}
|
||||||
APPEND(NEWSTR(ctx, s, strlen(s)));
|
APPEND(NEWSTR(c, s, strlen(s)));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: handle ctx->callParent frames too!
|
// FIXME: needs to honor subcontext list
|
||||||
static naRef f_caller(naContext ctx, naRef me, int argc, naRef* args)
|
static naRef f_caller(naContext c, naRef me, int argc, naRef* args)
|
||||||
{
|
{
|
||||||
int fidx;
|
int fidx;
|
||||||
struct Frame* frame;
|
struct Frame* frame;
|
||||||
naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
|
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;
|
fidx = (int)fr.num;
|
||||||
if(fidx > ctx->fTop - 1) return naNil();
|
if(fidx > c->fTop - 1) return naNil();
|
||||||
frame = &ctx->fStack[ctx->fTop - 1 - fidx];
|
frame = &c->fStack[c->fTop - 1 - fidx];
|
||||||
result = naNewVector(ctx);
|
result = naNewVector(c);
|
||||||
naVec_append(result, frame->locals);
|
naVec_append(result, frame->locals);
|
||||||
naVec_append(result, frame->func);
|
naVec_append(result, frame->func);
|
||||||
naVec_append(result, frame->func.ref.ptr.func->code.ref.ptr.code->srcFile);
|
naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
|
||||||
naVec_append(result, naNum(naGetLine(ctx, fidx)));
|
naVec_append(result, naNum(naGetLine(c, fidx)));
|
||||||
return result;
|
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;
|
int i;
|
||||||
naRef func, idx;
|
|
||||||
struct naFunc* f;
|
struct naFunc* f;
|
||||||
func = argc > 0 ? args[0] : naNil();
|
naRef func = argc > 0 ? args[0] : naNil();
|
||||||
idx = argc > 1 ? naNumValue(args[1]) : naNil();
|
naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
|
||||||
if(!IS_FUNC(func) || IS_NIL(idx))
|
if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
|
||||||
naRuntimeError(ctx, "bad arguments to closure()");
|
|
||||||
i = (int)idx.num;
|
i = (int)idx.num;
|
||||||
f = func.ref.ptr.func;
|
f = PTR(func).func;
|
||||||
while(i > 0 && f) { i--; f = f->next.ref.ptr.func; }
|
while(i > 0 && f) { i--; f = PTR(f->next).func; }
|
||||||
if(!f) return naNil();
|
if(!f) return naNil();
|
||||||
return f->namespace;
|
return f->namespace;
|
||||||
}
|
}
|
||||||
@@ -377,40 +417,38 @@ static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
|
|||||||
return -1;
|
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;
|
int start = 0;
|
||||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
|
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
|
||||||
naRuntimeError(ctx, "bad/missing argument to find");
|
|
||||||
if(argc > 2) start = (int)(naNumValue(args[2]).num);
|
if(argc > 2) start = (int)(naNumValue(args[2]).num);
|
||||||
return naNum(find(args[0].ref.ptr.str->data, args[0].ref.ptr.str->len,
|
return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len,
|
||||||
args[1].ref.ptr.str->data, args[1].ref.ptr.str->len,
|
PTR(args[1]).str->data, PTR(args[1]).str->len,
|
||||||
start));
|
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;
|
int sl, dl, i;
|
||||||
char *s, *d, *s0;
|
char *s, *d, *s0;
|
||||||
naRef result;
|
naRef result;
|
||||||
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1]))
|
if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
|
||||||
naRuntimeError(ctx, "bad/missing argument to split");
|
|
||||||
d = naStr_data(args[0]); dl = naStr_len(args[0]);
|
d = naStr_data(args[0]); dl = naStr_len(args[0]);
|
||||||
s = naStr_data(args[1]); sl = naStr_len(args[1]);
|
s = naStr_data(args[1]); sl = naStr_len(args[1]);
|
||||||
result = naNewVector(ctx);
|
result = naNewVector(c);
|
||||||
if(dl == 0) { // special case zero-length delimiter
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
s0 = s;
|
s0 = s;
|
||||||
for(i=0; i <= sl-dl; i++) {
|
for(i=0; i <= sl-dl; i++) {
|
||||||
if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
|
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;
|
s0 = s + i + dl;
|
||||||
i += dl - 1;
|
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;
|
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
|
// function, which is usually not threadsafe and often of limited
|
||||||
// precision. The 5x loop guarantees that we get a full double worth
|
// precision. The 5x loop guarantees that we get a full double worth
|
||||||
// of precision even for 15 bit (Win32...) rand() implementations.
|
// 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;
|
int i;
|
||||||
double r = 0;
|
double r = 0;
|
||||||
if(argc) {
|
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);
|
srand((unsigned int)args[0].num);
|
||||||
return naNil();
|
return naNil();
|
||||||
}
|
}
|
||||||
@@ -431,36 +469,91 @@ static naRef f_rand(naContext ctx, naRef me, int argc, naRef* args)
|
|||||||
return naNum(r);
|
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 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();
|
naRef next = argc > 2 ? args[2] : naNil();
|
||||||
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
|
if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
|
||||||
naRuntimeError(ctx, "bad argument to bind");
|
ARGERR();
|
||||||
func = naNewFunc(ctx, func.ref.ptr.func->code);
|
func = naNewFunc(c, PTR(func).func->code);
|
||||||
func.ref.ptr.func->namespace = hash;
|
PTR(func).func->namespace = hash;
|
||||||
func.ref.ptr.func->next = next;
|
PTR(func).func->next = next;
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct func { char* name; naCFunction func; };
|
/* We use the "SortRec" gadget for two reasons: first, because ANSI
|
||||||
static struct func funcs[] = {
|
* qsort() doesn't give us a mechanism for passing a "context" pointer
|
||||||
{ "size", size },
|
* to the comparison routine we have to store one in every sorted
|
||||||
{ "keys", keys },
|
* record. Second, using an index into the original vector here
|
||||||
{ "append", append },
|
* allows us to make the sort stable in the event of a zero returned
|
||||||
{ "pop", pop },
|
* from the Nasal comparison function. */
|
||||||
{ "setsize", setsize },
|
struct SortData { naContext ctx, subc; struct SortRec* recs;
|
||||||
{ "subvec", subvec },
|
naRef* elems; int n; naRef fn; };
|
||||||
{ "delete", delete },
|
struct SortRec { struct SortData* sd; int i; };
|
||||||
{ "int", intf },
|
|
||||||
{ "num", num },
|
static int sortcmp(struct SortRec* a, struct SortRec* b)
|
||||||
{ "streq", streq },
|
{
|
||||||
|
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 },
|
{ "cmp", f_cmp },
|
||||||
{ "substr", substr },
|
{ "substr", f_substr },
|
||||||
{ "chr", f_chr },
|
{ "chr", f_chr },
|
||||||
{ "contains", contains },
|
{ "contains", f_contains },
|
||||||
{ "typeof", typeOf },
|
{ "typeof", f_typeof },
|
||||||
|
{ "ghosttype", f_ghosttype },
|
||||||
{ "compile", f_compile },
|
{ "compile", f_compile },
|
||||||
{ "call", f_call },
|
{ "call", f_call },
|
||||||
{ "die", f_die },
|
{ "die", f_die },
|
||||||
@@ -471,17 +564,11 @@ static struct func funcs[] = {
|
|||||||
{ "split", f_split },
|
{ "split", f_split },
|
||||||
{ "rand", f_rand },
|
{ "rand", f_rand },
|
||||||
{ "bind", f_bind },
|
{ "bind", f_bind },
|
||||||
|
{ "sort", f_sort },
|
||||||
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
naRef naStdLib(naContext c)
|
naRef naInit_std(naContext c)
|
||||||
{
|
{
|
||||||
naRef namespace = naNewHash(c);
|
return naGenLib(c, funcs);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-28
@@ -1,16 +1,32 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nasal.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)
|
static naRef f_sin(naContext c, naRef me, int argc, naRef* args)
|
||||||
{
|
{
|
||||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||||
if(naIsNil(a))
|
if(naIsNil(a))
|
||||||
naRuntimeError(c, "non numeric argument to sin()");
|
naRuntimeError(c, "non numeric argument to sin()");
|
||||||
a.num = sin(a.num);
|
a.num = sin(a.num);
|
||||||
return a;
|
return VALIDATE(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_cos(naContext c, naRef me, int argc, naRef* args)
|
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))
|
if(naIsNil(a))
|
||||||
naRuntimeError(c, "non numeric argument to cos()");
|
naRuntimeError(c, "non numeric argument to cos()");
|
||||||
a.num = cos(a.num);
|
a.num = cos(a.num);
|
||||||
return a;
|
return VALIDATE(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_exp(naContext c, naRef me, int argc, naRef* args)
|
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))
|
if(naIsNil(a))
|
||||||
naRuntimeError(c, "non numeric argument to exp()");
|
naRuntimeError(c, "non numeric argument to exp()");
|
||||||
a.num = exp(a.num);
|
a.num = exp(a.num);
|
||||||
return a;
|
return VALIDATE(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_ln(naContext c, naRef me, int argc, naRef* args)
|
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))
|
if(naIsNil(a))
|
||||||
naRuntimeError(c, "non numeric argument to ln()");
|
naRuntimeError(c, "non numeric argument to ln()");
|
||||||
a.num = log(a.num);
|
a.num = log(a.num);
|
||||||
return a;
|
return VALIDATE(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_sqrt(naContext c, naRef me, int argc, naRef* args)
|
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))
|
if(naIsNil(a))
|
||||||
naRuntimeError(c, "non numeric argument to sqrt()");
|
naRuntimeError(c, "non numeric argument to sqrt()");
|
||||||
a.num = sqrt(a.num);
|
a.num = sqrt(a.num);
|
||||||
return a;
|
return VALIDATE(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static naRef f_atan2(naContext c, naRef me, int argc, naRef* args)
|
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))
|
if(naIsNil(a) || naIsNil(b))
|
||||||
naRuntimeError(c, "non numeric argument to atan2()");
|
naRuntimeError(c, "non numeric argument to atan2()");
|
||||||
a.num = atan2(a.num, b.num);
|
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 },
|
{ "sin", f_sin },
|
||||||
{ "cos", f_cos },
|
{ "cos", f_cos },
|
||||||
{ "exp", f_exp },
|
{ "exp", f_exp },
|
||||||
{ "ln", f_ln },
|
{ "ln", f_ln },
|
||||||
{ "sqrt", f_sqrt },
|
{ "sqrt", f_sqrt },
|
||||||
{ "atan2", f_atan2 },
|
{ "atan2", f_atan2 },
|
||||||
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
naRef naMathLib(naContext c)
|
naRef naInit_math(naContext c)
|
||||||
{
|
{
|
||||||
naRef name, namespace = naNewHash(c);
|
naRef ns = naGenLib(c, funcs);
|
||||||
int i, n = sizeof(funcs)/sizeof(struct func);
|
naAddSym(c, ns, "pi", naNum(3.14159265358979323846));
|
||||||
for(i=0; i<n; i++) {
|
naAddSym(c, ns, "e", naNum(2.7182818284590452354));
|
||||||
naRef code = naNewCCode(c, funcs[i].func);
|
return ns;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-25
@@ -23,14 +23,13 @@ void naTempSave(naContext c, naRef r)
|
|||||||
naFree(c->temps);
|
naFree(c->temps);
|
||||||
c->temps = newtemps;
|
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 naObj(int type, struct naObj* o)
|
||||||
{
|
{
|
||||||
naRef r;
|
naRef r;
|
||||||
r.ref.reftag = NASAL_REFTAG;
|
SETPTR(r, o);
|
||||||
r.ref.ptr.obj = o;
|
|
||||||
o->type = type;
|
o->type = type;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -78,23 +77,23 @@ naRef naNew(struct Context* c, int type)
|
|||||||
naRef naNewString(struct Context* c)
|
naRef naNewString(struct Context* c)
|
||||||
{
|
{
|
||||||
naRef s = naNew(c, T_STR);
|
naRef s = naNew(c, T_STR);
|
||||||
s.ref.ptr.str->len = 0;
|
PTR(s).str->len = 0;
|
||||||
s.ref.ptr.str->data = 0;
|
PTR(s).str->data = 0;
|
||||||
s.ref.ptr.str->hashcode = 0;
|
PTR(s).str->hashcode = 0;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNewVector(struct Context* c)
|
naRef naNewVector(struct Context* c)
|
||||||
{
|
{
|
||||||
naRef r = naNew(c, T_VEC);
|
naRef r = naNew(c, T_VEC);
|
||||||
r.ref.ptr.vec->rec = 0;
|
PTR(r).vec->rec = 0;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNewHash(struct Context* c)
|
naRef naNewHash(struct Context* c)
|
||||||
{
|
{
|
||||||
naRef r = naNew(c, T_HASH);
|
naRef r = naNew(c, T_HASH);
|
||||||
r.ref.ptr.hash->rec = 0;
|
PTR(r).hash->rec = 0;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,59 +105,57 @@ naRef naNewCode(struct Context* c)
|
|||||||
naRef naNewCCode(struct Context* c, naCFunction fptr)
|
naRef naNewCCode(struct Context* c, naCFunction fptr)
|
||||||
{
|
{
|
||||||
naRef r = naNew(c, T_CCODE);
|
naRef r = naNew(c, T_CCODE);
|
||||||
r.ref.ptr.ccode->fptr = fptr;
|
PTR(r).ccode->fptr = fptr;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNewFunc(struct Context* c, naRef code)
|
naRef naNewFunc(struct Context* c, naRef code)
|
||||||
{
|
{
|
||||||
naRef func = naNew(c, T_FUNC);
|
naRef func = naNew(c, T_FUNC);
|
||||||
func.ref.ptr.func->code = code;
|
PTR(func).func->code = code;
|
||||||
func.ref.ptr.func->namespace = naNil();
|
PTR(func).func->namespace = naNil();
|
||||||
func.ref.ptr.func->next = naNil();
|
PTR(func).func->next = naNil();
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
|
naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
|
||||||
{
|
{
|
||||||
naRef ghost = naNew(c, T_GHOST);
|
naRef ghost = naNew(c, T_GHOST);
|
||||||
ghost.ref.ptr.ghost->gtype = type;
|
PTR(ghost).ghost->gtype = type;
|
||||||
ghost.ref.ptr.ghost->ptr = ptr;
|
PTR(ghost).ghost->ptr = ptr;
|
||||||
return ghost;
|
return ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
naGhostType* naGhost_type(naRef ghost)
|
naGhostType* naGhost_type(naRef ghost)
|
||||||
{
|
{
|
||||||
if(!IS_GHOST(ghost)) return 0;
|
if(!IS_GHOST(ghost)) return 0;
|
||||||
return ghost.ref.ptr.ghost->gtype;
|
return PTR(ghost).ghost->gtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* naGhost_ptr(naRef ghost)
|
void* naGhost_ptr(naRef ghost)
|
||||||
{
|
{
|
||||||
if(!IS_GHOST(ghost)) return 0;
|
if(!IS_GHOST(ghost)) return 0;
|
||||||
return ghost.ref.ptr.ghost->ptr;
|
return PTR(ghost).ghost->ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNil()
|
naRef naNil()
|
||||||
{
|
{
|
||||||
naRef r;
|
naRef r;
|
||||||
r.ref.reftag = NASAL_REFTAG;
|
SETPTR(r, 0);
|
||||||
r.ref.ptr.obj = 0;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naNum(double num)
|
naRef naNum(double num)
|
||||||
{
|
{
|
||||||
naRef r;
|
naRef r;
|
||||||
r.ref.reftag = ~NASAL_REFTAG;
|
SETNUM(r, num);
|
||||||
r.num = num;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int naEqual(naRef a, naRef b)
|
int naEqual(naRef a, naRef b)
|
||||||
{
|
{
|
||||||
double na=0, nb=0;
|
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)
|
return 1; // Object identity (and nil == nil)
|
||||||
if(IS_NIL(a) || IS_NIL(b))
|
if(IS_NIL(a) || IS_NIL(b))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -182,10 +179,10 @@ int naStrEqual(naRef a, naRef b)
|
|||||||
int i;
|
int i;
|
||||||
if(!(IS_STR(a) && IS_STR(b)))
|
if(!(IS_STR(a) && IS_STR(b)))
|
||||||
return 0;
|
return 0;
|
||||||
if(a.ref.ptr.str->len != b.ref.ptr.str->len)
|
if(PTR(a).str->len != PTR(b).str->len)
|
||||||
return 0;
|
return 0;
|
||||||
for(i=0; i<a.ref.ptr.str->len; i++)
|
for(i=0; i<PTR(a).str->len; i++)
|
||||||
if(a.ref.ptr.str->data[i] != b.ref.ptr.str->data[i])
|
if(PTR(a).str->data[i] != PTR(b).str->data[i])
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -214,3 +211,24 @@ int naIsFunc(naRef r) { return IS_FUNC(r); }
|
|||||||
int naIsCode(naRef r) { return IS_CODE(r); }
|
int naIsCode(naRef r) { return IS_CODE(r); }
|
||||||
int naIsCCode(naRef r) { return IS_CCODE(r); }
|
int naIsCCode(naRef r) { return IS_CCODE(r); }
|
||||||
int naIsGhost(naRef r) { return IS_GHOST(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" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BYTE_ORDER
|
#include "naref.h"
|
||||||
|
|
||||||
# if (BSD >= 199103)
|
#if __GNUC__ > 2
|
||||||
# include <machine/endian.h>
|
/* This marks the function as having no side effects and depending on
|
||||||
# elif defined(__CYGWIN__) || defined(__MINGW32__)
|
* nothing but its arguments, which allows the optimizer to avoid
|
||||||
# include <sys/param.h>
|
* duplicate calls to naNil(). */
|
||||||
# elif defined(linux)
|
#define GCC_PURE __attribute__((__pure__))
|
||||||
# include <endian.h>
|
#else
|
||||||
# else
|
#define GCC_PURE
|
||||||
# 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
|
|
||||||
#endif
|
#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;
|
typedef struct Context* naContext;
|
||||||
|
|
||||||
// The function signature for an extension function:
|
// The function signature for an extension function:
|
||||||
@@ -80,7 +24,21 @@ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
|
|||||||
naContext naNewContext();
|
naContext naNewContext();
|
||||||
void naFreeContext(naContext c);
|
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.
|
// referenced by it) from being garbage collected.
|
||||||
void naSave(naContext ctx, naRef obj);
|
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.
|
// temporaries to protect them before passing back into a naCall.
|
||||||
void naTempSave(naContext c, naRef r);
|
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,
|
naRef naParseCode(naContext c, naRef srcFile, int firstLine,
|
||||||
char* buf, int len, int* errLine);
|
char* buf, int len, int* errLine);
|
||||||
|
|
||||||
// Binds a bare code object (as returned from naParseCode) with a
|
// Binds a bare code object (as returned from naParseCode) with a
|
||||||
// closure object (a hash) to act as the outer scope / namespace.
|
// 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);
|
naRef naBindFunction(naContext ctx, naRef code, naRef closure);
|
||||||
|
|
||||||
// Similar, but it binds to the current context's closure (i.e. the
|
// Similar, but it binds to the current context's closure (i.e. the
|
||||||
// namespace at the top of the current call stack).
|
// namespace at the top of the current call stack).
|
||||||
naRef naBindToContext(naContext ctx, naRef code);
|
naRef naBindToContext(naContext ctx, naRef code);
|
||||||
|
|
||||||
// Call a code or function object with the specifed arguments "on" the
|
// Call a code or function object with the specified arguments "on"
|
||||||
// specified object and using the specified hash for the local
|
// the specified object and using the specified hash for the local
|
||||||
// variables. Any of args, obj or locals may be nil.
|
// variables. Passing a null args array skips the parameter variables
|
||||||
naRef naCall(naContext ctx, naRef func, int argc, naRef* args, naRef obj, naRef locals);
|
// (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
|
// 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
|
// longjmp call to a handler in naCall() and DOES NOT RETURN. It is
|
||||||
// intended for use in library code that cannot otherwise report an
|
// intended for use in library code that cannot otherwise report an
|
||||||
// error via the return value, and MUST be used carefully. If in
|
// error via the return value, and MUST be used carefully. If in
|
||||||
// doubt, return naNil() as your error condition.
|
// doubt, return naNil() as your error condition. Works like
|
||||||
void naRuntimeError(naContext ctx, char* msg);
|
// printf().
|
||||||
|
void naRuntimeError(naContext c, const char* fmt, ...);
|
||||||
|
|
||||||
// Call a method on an object (NOTE: func is a function binding, *not*
|
// "Re-throws" a runtime error caught from the subcontext. Acts as a
|
||||||
// a code object as returned from naParseCode).
|
// naRuntimeError() called on the parent context. Does not return.
|
||||||
naRef naMethod(naContext ctx, naRef func, naRef object);
|
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
|
// Returns a hash containing functions from the Nasal standard library
|
||||||
// Useful for passing as a namespace to an initial function call
|
// 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
|
// Ditto, for other core libraries
|
||||||
naRef naMathLib(naContext c);
|
naRef naInit_math(naContext c);
|
||||||
naRef naBitsLib(naContext c);
|
naRef naInit_bits(naContext c);
|
||||||
naRef naIOLib(naContext c);
|
naRef naInit_io(naContext c);
|
||||||
naRef naRegexLib(naContext c);
|
naRef naInit_regex(naContext c);
|
||||||
naRef naUnixLib(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 naStackDepth(naContext ctx);
|
||||||
int naGetLine(naContext ctx, int frame);
|
int naGetLine(naContext ctx, int frame);
|
||||||
naRef naGetSourceFile(naContext ctx, int frame);
|
naRef naGetSourceFile(naContext ctx, int frame);
|
||||||
char* naGetError(naContext ctx);
|
char* naGetError(naContext ctx);
|
||||||
|
|
||||||
// Type predicates
|
// Type predicates
|
||||||
int naIsNil(naRef r);
|
int naIsNil(naRef r) GCC_PURE;
|
||||||
int naIsNum(naRef r);
|
int naIsNum(naRef r) GCC_PURE;
|
||||||
int naIsString(naRef r);
|
int naIsString(naRef r) GCC_PURE;
|
||||||
int naIsScalar(naRef r);
|
int naIsScalar(naRef r) GCC_PURE;
|
||||||
int naIsVector(naRef r);
|
int naIsVector(naRef r) GCC_PURE;
|
||||||
int naIsHash(naRef r);
|
int naIsHash(naRef r) GCC_PURE;
|
||||||
int naIsCode(naRef r);
|
int naIsCode(naRef r) GCC_PURE;
|
||||||
int naIsFunc(naRef r);
|
int naIsFunc(naRef r) GCC_PURE;
|
||||||
int naIsCCode(naRef r);
|
int naIsCCode(naRef r) GCC_PURE;
|
||||||
|
|
||||||
// Allocators/generators:
|
// Allocators/generators:
|
||||||
naRef naNil();
|
naRef naNil() GCC_PURE;
|
||||||
naRef naNum(double num);
|
naRef naNum(double num) GCC_PURE;
|
||||||
naRef naNewString(naContext c);
|
naRef naNewString(naContext c);
|
||||||
naRef naNewVector(naContext c);
|
naRef naNewVector(naContext c);
|
||||||
naRef naNewHash(naContext c);
|
naRef naNewHash(naContext c);
|
||||||
@@ -158,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code);
|
|||||||
naRef naNewCCode(naContext c, naCFunction fptr);
|
naRef naNewCCode(naContext c, naCFunction fptr);
|
||||||
|
|
||||||
// Some useful conversion/comparison routines
|
// Some useful conversion/comparison routines
|
||||||
int naEqual(naRef a, naRef b);
|
int naEqual(naRef a, naRef b) GCC_PURE;
|
||||||
int naStrEqual(naRef a, naRef b);
|
int naStrEqual(naRef a, naRef b) GCC_PURE;
|
||||||
int naTrue(naRef b);
|
int naTrue(naRef b) GCC_PURE;
|
||||||
naRef naNumValue(naRef n);
|
naRef naNumValue(naRef n) GCC_PURE;
|
||||||
naRef naStringValue(naContext c, naRef n);
|
naRef naStringValue(naContext c, naRef n);
|
||||||
|
|
||||||
// String utilities:
|
// String utilities:
|
||||||
@@ -192,6 +180,7 @@ void naHash_keys(naRef dst, naRef hash);
|
|||||||
// Ghost utilities:
|
// Ghost utilities:
|
||||||
typedef struct naGhostType {
|
typedef struct naGhostType {
|
||||||
void (*destroy)(void* ghost);
|
void (*destroy)(void* ghost);
|
||||||
|
const char* name;
|
||||||
} naGhostType;
|
} naGhostType;
|
||||||
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
||||||
naGhostType* naGhost_type(naRef 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
|
// 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
|
// modify Nasal data without fear that such data may be "lost" by the
|
||||||
// garbage collector (the C stack is not examined in GC!). This
|
// garbage collector (nasal data the C stack is not examined in GC!).
|
||||||
// disallows garbage collection until the current thread can be
|
// This disallows garbage collection until the current thread can be
|
||||||
// blocked. The lock should be acquired whenever modifications to
|
// blocked. The lock should be acquired whenever nasal objects are
|
||||||
// Nasal objects are made. It need not be acquired when only read
|
// being modified. It need not be acquired when only read access is
|
||||||
// access is needed. It MUST NOT be acquired by naCFunction's, as
|
// needed, PRESUMING that the Nasal data being read is findable by the
|
||||||
// those are called with the lock already held; acquiring two locks
|
// collector (via naSave, for example) and that another Nasal thread
|
||||||
// for the same thread will cause a deadlock when the GC is invoked.
|
// cannot or will not delete the reference to the data. It MUST NOT
|
||||||
// It should be UNLOCKED by naCFunction's when they are about to do
|
// be acquired by naCFunction's, as those are called with the lock
|
||||||
// any long term non-nasal processing and/or blocking I/O.
|
// 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 naModLock();
|
||||||
void naModUnlock();
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+82
-8
@@ -1,11 +1,10 @@
|
|||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
||||||
// Static precedence table, from low (loose binding, do first) to high
|
// Static precedence table, from low (loose binding, do first) to high
|
||||||
// (tight binding, do last).
|
// (tight binding, do last).
|
||||||
enum { PREC_BINARY, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
|
||||||
|
|
||||||
#define MAX_PREC_TOKS 6
|
#define MAX_PREC_TOKS 6
|
||||||
struct precedence {
|
struct precedence {
|
||||||
int toks[MAX_PREC_TOKS];
|
int toks[MAX_PREC_TOKS];
|
||||||
@@ -32,8 +31,10 @@ struct precedence {
|
|||||||
|
|
||||||
void naParseError(struct Parser* p, char* msg, int line)
|
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->err = msg;
|
||||||
p->errLine = line;
|
|
||||||
longjmp(p->jumpHandle, 1);
|
longjmp(p->jumpHandle, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,11 +206,83 @@ static struct Token* emptyToken(struct Parser* p)
|
|||||||
return t;
|
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
|
// Fixes up parenting for obvious parsing situations, like code blocks
|
||||||
// being the child of a func keyword, etc...
|
// being the child of a func keyword, etc...
|
||||||
static void fixBlockStructure(struct Parser* p, struct Token* start)
|
static void fixBlockStructure(struct Parser* p, struct Token* start)
|
||||||
{
|
{
|
||||||
struct Token *t, *c;
|
struct Token *t, *c;
|
||||||
|
fixBracelessBlocks(p, start);
|
||||||
t = start;
|
t = start;
|
||||||
while(t) {
|
while(t) {
|
||||||
switch(t->type) {
|
switch(t->type) {
|
||||||
@@ -287,8 +360,8 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
|||||||
addSemi = 1;
|
addSemi = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(t->next && t->next->type == TOK_SEMI)
|
if(!t->next || t->next->type == TOK_SEMI || t->next->type == TOK_COMMA)
|
||||||
addSemi = 0; // don't bother if it's already there!
|
addSemi = 0; // don't bother, no need
|
||||||
if(addSemi) {
|
if(addSemi) {
|
||||||
struct Token* semi = emptyToken(p);
|
struct Token* semi = emptyToken(p);
|
||||||
semi->type = TOK_SEMI;
|
semi->type = TOK_SEMI;
|
||||||
@@ -297,6 +370,7 @@ static void fixBlockStructure(struct Parser* p, struct Token* start)
|
|||||||
semi->prev = t;
|
semi->prev = t;
|
||||||
semi->parent = t->parent;
|
semi->parent = t->parent;
|
||||||
if(semi->next) semi->next->prev = semi;
|
if(semi->next) semi->next->prev = semi;
|
||||||
|
else semi->parent->lastChild = semi;
|
||||||
t->next = semi;
|
t->next = semi;
|
||||||
t = semi; // don't bother checking the new one
|
t = semi; // don't bother checking the new one
|
||||||
}
|
}
|
||||||
@@ -455,6 +529,8 @@ static struct Token* parsePrecedence(struct Parser* p,
|
|||||||
if(!top)
|
if(!top)
|
||||||
return parsePrecedence(p, start, end, level+1);
|
return parsePrecedence(p, start, end, level+1);
|
||||||
|
|
||||||
|
top->rule = rule;
|
||||||
|
|
||||||
if(left) {
|
if(left) {
|
||||||
left->next = right;
|
left->next = right;
|
||||||
left->prev = 0;
|
left->prev = 0;
|
||||||
@@ -508,7 +584,7 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
|||||||
// Catch parser errors here.
|
// Catch parser errors here.
|
||||||
*errLine = 0;
|
*errLine = 0;
|
||||||
if(setjmp(p.jumpHandle)) {
|
if(setjmp(p.jumpHandle)) {
|
||||||
c->error = p.err;
|
strncpy(c->error, p.err, sizeof(c->error));
|
||||||
*errLine = p.errLine;
|
*errLine = p.errLine;
|
||||||
return naNil();
|
return naNil();
|
||||||
}
|
}
|
||||||
@@ -540,5 +616,3 @@ naRef naParseCode(struct Context* c, naRef srcFile, int firstLine,
|
|||||||
|
|
||||||
return codeObj;
|
return codeObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,15 @@ enum {
|
|||||||
TOK_FORINDEX
|
TOK_FORINDEX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Precedence rules
|
||||||
|
enum { PREC_BINARY=1, PREC_REVERSE, PREC_PREFIX, PREC_SUFFIX };
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
int type;
|
int type;
|
||||||
int line;
|
int line;
|
||||||
char* str;
|
char* str;
|
||||||
int strlen;
|
int strlen;
|
||||||
|
int rule;
|
||||||
double num;
|
double num;
|
||||||
struct Token* parent;
|
struct Token* parent;
|
||||||
struct Token* next;
|
struct Token* next;
|
||||||
@@ -94,6 +98,7 @@ void naParseInit(struct Parser* p);
|
|||||||
void* naParseAlloc(struct Parser* p, int bytes);
|
void* naParseAlloc(struct Parser* p, int bytes);
|
||||||
void naParseDestroy(struct Parser* p);
|
void naParseDestroy(struct Parser* p);
|
||||||
void naLex(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);
|
naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist);
|
||||||
|
|
||||||
void naParse(struct Parser* p);
|
void naParse(struct Parser* p);
|
||||||
|
|||||||
+16
-16
@@ -14,13 +14,13 @@ static int fromnum(double val, unsigned char* s);
|
|||||||
int naStr_len(naRef s)
|
int naStr_len(naRef s)
|
||||||
{
|
{
|
||||||
if(!IS_STR(s)) return 0;
|
if(!IS_STR(s)) return 0;
|
||||||
return s.ref.ptr.str->len;
|
return PTR(s).str->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* naStr_data(naRef s)
|
char* naStr_data(naRef s)
|
||||||
{
|
{
|
||||||
if(!IS_STR(s)) return 0;
|
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)
|
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)
|
naRef naStr_buf(naRef dst, int len)
|
||||||
{
|
{
|
||||||
setlen(dst.ref.ptr.str, len);
|
setlen(PTR(dst).str, len);
|
||||||
naBZero(dst.ref.ptr.str->data, len);
|
naBZero(PTR(dst).str->data, len);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naStr_fromdata(naRef dst, char* data, int len)
|
naRef naStr_fromdata(naRef dst, char* data, int len)
|
||||||
{
|
{
|
||||||
if(!IS_STR(dst)) return naNil();
|
if(!IS_STR(dst)) return naNil();
|
||||||
setlen(dst.ref.ptr.str, len);
|
setlen(PTR(dst).str, len);
|
||||||
memcpy(dst.ref.ptr.str->data, data, len);
|
memcpy(PTR(dst).str->data, data, len);
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naStr_concat(naRef dest, naRef s1, naRef s2)
|
naRef naStr_concat(naRef dest, naRef s1, naRef s2)
|
||||||
{
|
{
|
||||||
struct naStr* dst = dest.ref.ptr.str;
|
struct naStr* dst = PTR(dest).str;
|
||||||
struct naStr* a = s1.ref.ptr.str;
|
struct naStr* a = PTR(s1).str;
|
||||||
struct naStr* b = s2.ref.ptr.str;
|
struct naStr* b = PTR(s2).str;
|
||||||
if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
|
if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
|
||||||
setlen(dst, a->len + b->len);
|
setlen(dst, a->len + b->len);
|
||||||
memcpy(dst->data, a->data, a->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)
|
naRef naStr_substr(naRef dest, naRef str, int start, int len)
|
||||||
{
|
{
|
||||||
struct naStr* dst = dest.ref.ptr.str;
|
struct naStr* dst = PTR(dest).str;
|
||||||
struct naStr* s = str.ref.ptr.str;
|
struct naStr* s = PTR(str).str;
|
||||||
if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
|
if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
|
||||||
if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
|
if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
|
||||||
setlen(dst, len);
|
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)
|
int naStr_equal(naRef s1, naRef s2)
|
||||||
{
|
{
|
||||||
struct naStr* a = s1.ref.ptr.str;
|
struct naStr* a = PTR(s1).str;
|
||||||
struct naStr* b = s2.ref.ptr.str;
|
struct naStr* b = PTR(s2).str;
|
||||||
if(a->data == b->data) return 1;
|
if(a->data == b->data) return 1;
|
||||||
if(a->len != b->len) return 0;
|
if(a->len != b->len) return 0;
|
||||||
if(memcmp(a->data, b->data, a->len) == 0) return 1;
|
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)
|
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];
|
unsigned char buf[DIGITS+8];
|
||||||
setlen(dst, fromnum(num, buf));
|
setlen(dst, fromnum(num, buf));
|
||||||
memcpy(dst->data, buf, dst->len);
|
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)
|
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)
|
int naStr_numeric(naRef str)
|
||||||
{
|
{
|
||||||
double dummy;
|
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)
|
void naStr_gcclean(struct naStr* str)
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ void* naNewLock()
|
|||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void naFreeLock(void* lock)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(lock);
|
||||||
|
naFree(lock);
|
||||||
|
}
|
||||||
|
|
||||||
void naLock(void* lock)
|
void naLock(void* lock)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock((pthread_mutex_t*)lock);
|
pthread_mutex_lock((pthread_mutex_t*)lock);
|
||||||
@@ -35,6 +41,14 @@ void* naNewSem()
|
|||||||
return sem;
|
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)
|
void naSemDown(void* sh)
|
||||||
{
|
{
|
||||||
struct naSem* sem = (struct naSem*)sh;
|
struct naSem* sem = (struct naSem*)sh;
|
||||||
@@ -45,11 +59,11 @@ void naSemDown(void* sh)
|
|||||||
pthread_mutex_unlock(&sem->lock);
|
pthread_mutex_unlock(&sem->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void naSemUpAll(void* sh, int count)
|
void naSemUp(void* sh, int count)
|
||||||
{
|
{
|
||||||
struct naSem* sem = (struct naSem*)sh;
|
struct naSem* sem = (struct naSem*)sh;
|
||||||
pthread_mutex_lock(&sem->lock);
|
pthread_mutex_lock(&sem->lock);
|
||||||
sem->count = count;
|
sem->count += count;
|
||||||
pthread_cond_broadcast(&sem->cvar);
|
pthread_cond_broadcast(&sem->cvar);
|
||||||
pthread_mutex_unlock(&sem->lock);
|
pthread_mutex_unlock(&sem->lock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ void* naNewLock()
|
|||||||
|
|
||||||
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
|
void naLock(void* lock) { EnterCriticalSection((LPCRITICAL_SECTION)lock); }
|
||||||
void naUnlock(void* lock) { LeaveCriticalSection((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* naNewSem() { return CreateSemaphore(0, 0, MAX_SEM_COUNT, 0); }
|
||||||
void naSemDown(void* sem) { WaitForSingleObject((HANDLE)sem, INFINITE); }
|
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
|
#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;
|
return vr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vecrealloc(struct naVec* v)
|
static void resize(struct naVec* v)
|
||||||
{
|
{
|
||||||
struct VecRec* vr = newvecrec(v->rec);
|
struct VecRec* vr = newvecrec(v->rec);
|
||||||
naGC_swapfree((void**)&(v->rec), vr);
|
naGC_swapfree((void**)&(v->rec), vr);
|
||||||
@@ -28,7 +28,7 @@ void naVec_gcclean(struct naVec* v)
|
|||||||
naRef naVec_get(naRef v, int i)
|
naRef naVec_get(naRef v, int i)
|
||||||
{
|
{
|
||||||
if(IS_VEC(v)) {
|
if(IS_VEC(v)) {
|
||||||
struct VecRec* r = v.ref.ptr.vec->rec;
|
struct VecRec* r = PTR(v).vec->rec;
|
||||||
if(r) {
|
if(r) {
|
||||||
if(i < 0) i += r->size;
|
if(i < 0) i += r->size;
|
||||||
if(i >= 0 && i < r->size) return r->array[i];
|
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)
|
void naVec_set(naRef vec, int i, naRef o)
|
||||||
{
|
{
|
||||||
if(IS_VEC(vec)) {
|
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;
|
if(r && i >= r->size) return;
|
||||||
r->array[i] = o;
|
r->array[i] = o;
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ void naVec_set(naRef vec, int i, naRef o)
|
|||||||
int naVec_size(naRef v)
|
int naVec_size(naRef v)
|
||||||
{
|
{
|
||||||
if(IS_VEC(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 r ? r->size : 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -58,10 +58,10 @@ int naVec_size(naRef v)
|
|||||||
int naVec_append(naRef vec, naRef o)
|
int naVec_append(naRef vec, naRef o)
|
||||||
{
|
{
|
||||||
if(IS_VEC(vec)) {
|
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) {
|
while(!r || r->size >= r->alloced) {
|
||||||
vecrealloc(vec.ref.ptr.vec);
|
resize(PTR(vec).vec);
|
||||||
r = vec.ref.ptr.vec->rec;
|
r = PTR(vec).vec->rec;
|
||||||
}
|
}
|
||||||
r->array[r->size] = o;
|
r->array[r->size] = o;
|
||||||
return r->size++;
|
return r->size++;
|
||||||
@@ -72,26 +72,25 @@ int naVec_append(naRef vec, naRef o)
|
|||||||
void naVec_setsize(naRef vec, int sz)
|
void naVec_setsize(naRef vec, int sz)
|
||||||
{
|
{
|
||||||
int i;
|
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);
|
struct VecRec* nv = naAlloc(sizeof(struct VecRec) + sizeof(naRef) * sz);
|
||||||
nv->size = sz;
|
nv->size = sz;
|
||||||
nv->alloced = sz;
|
nv->alloced = sz;
|
||||||
for(i=0; i<sz; i++)
|
for(i=0; i<sz; i++)
|
||||||
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
|
nv->array[i] = (v && i < v->size) ? v->array[i] : naNil();
|
||||||
naFree(v);
|
naGC_swapfree((void**)&(PTR(vec).vec->rec), nv);
|
||||||
vec.ref.ptr.vec->rec = nv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
naRef naVec_removelast(naRef vec)
|
naRef naVec_removelast(naRef vec)
|
||||||
{
|
{
|
||||||
naRef o;
|
naRef o;
|
||||||
if(IS_VEC(vec)) {
|
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();
|
if(!v || v->size == 0) return naNil();
|
||||||
o = v->array[v->size - 1];
|
o = v->array[v->size - 1];
|
||||||
v->size--;
|
v->size--;
|
||||||
if(v->size < (v->alloced >> 1))
|
if(v->size < (v->alloced >> 1))
|
||||||
vecrealloc(vec.ref.ptr.vec);
|
resize(PTR(vec).vec);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
return naNil();
|
return naNil();
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ SGNotCondition::SGNotCondition (SGCondition * condition)
|
|||||||
|
|
||||||
SGNotCondition::~SGNotCondition ()
|
SGNotCondition::~SGNotCondition ()
|
||||||
{
|
{
|
||||||
delete _condition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -86,8 +85,6 @@ SGAndCondition::SGAndCondition ()
|
|||||||
|
|
||||||
SGAndCondition::~SGAndCondition ()
|
SGAndCondition::~SGAndCondition ()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < _conditions.size(); i++)
|
|
||||||
delete _conditions[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -119,8 +116,6 @@ SGOrCondition::SGOrCondition ()
|
|||||||
|
|
||||||
SGOrCondition::~SGOrCondition ()
|
SGOrCondition::~SGOrCondition ()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < _conditions.size(); i++)
|
|
||||||
delete _conditions[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -398,13 +393,11 @@ SGConditional::SGConditional ()
|
|||||||
|
|
||||||
SGConditional::~SGConditional ()
|
SGConditional::~SGConditional ()
|
||||||
{
|
{
|
||||||
delete _condition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SGConditional::setCondition (SGCondition * condition)
|
SGConditional::setCondition (SGCondition * condition)
|
||||||
{
|
{
|
||||||
delete _condition;
|
|
||||||
_condition = condition;
|
_condition = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
*
|
*
|
||||||
* This class should migrate to somewhere more general.
|
* This class should migrate to somewhere more general.
|
||||||
*/
|
*/
|
||||||
class SGCondition
|
class SGCondition : public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SGCondition ();
|
SGCondition ();
|
||||||
@@ -63,12 +64,11 @@ private:
|
|||||||
class SGNotCondition : public SGCondition
|
class SGNotCondition : public SGCondition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// transfer pointer ownership
|
|
||||||
SGNotCondition (SGCondition * condition);
|
SGNotCondition (SGCondition * condition);
|
||||||
virtual ~SGNotCondition ();
|
virtual ~SGNotCondition ();
|
||||||
virtual bool test () const;
|
virtual bool test () const;
|
||||||
private:
|
private:
|
||||||
SGCondition * _condition;
|
SGSharedPtr<SGCondition> _condition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ public:
|
|||||||
// transfer pointer ownership
|
// transfer pointer ownership
|
||||||
virtual void addCondition (SGCondition * condition);
|
virtual void addCondition (SGCondition * condition);
|
||||||
private:
|
private:
|
||||||
vector<SGCondition *> _conditions;
|
std::vector<SGSharedPtr<SGCondition> > _conditions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
// transfer pointer ownership
|
// transfer pointer ownership
|
||||||
virtual void addCondition (SGCondition * condition);
|
virtual void addCondition (SGCondition * condition);
|
||||||
private:
|
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
|
* invoke the test() method whenever it needs to decide whether to
|
||||||
* active itself, draw itself, and so on.
|
* active itself, draw itself, and so on.
|
||||||
*/
|
*/
|
||||||
class SGConditional
|
class SGConditional : public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SGConditional ();
|
SGConditional ();
|
||||||
@@ -156,7 +156,7 @@ public:
|
|||||||
virtual const SGCondition * getCondition () const { return _condition; }
|
virtual const SGCondition * getCondition () const { return _condition; }
|
||||||
virtual bool test () const;
|
virtual bool test () const;
|
||||||
private:
|
private:
|
||||||
SGCondition * _condition;
|
SGSharedPtr<SGCondition> _condition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+84
-36
@@ -595,11 +595,11 @@ void
|
|||||||
SGPropertyNode::trace_write () const
|
SGPropertyNode::trace_write () const
|
||||||
{
|
{
|
||||||
#if PROPS_STANDALONE
|
#if PROPS_STANDALONE
|
||||||
cerr << "TRACE: Write node " << getPath () << ", value\""
|
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||||
<< make_string() << '"' << endl;
|
<< make_string() << '"' << endl;
|
||||||
#else
|
#else
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
|
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
|
||||||
<< ", value\"" << make_string() << '"');
|
<< ", value \"" << make_string() << '"');
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,7 +613,7 @@ SGPropertyNode::trace_read () const
|
|||||||
cerr << "TRACE: Write node " << getPath () << ", value \""
|
cerr << "TRACE: Write node " << getPath () << ", value \""
|
||||||
<< make_string() << '"' << endl;
|
<< make_string() << '"' << endl;
|
||||||
#else
|
#else
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
|
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
|
||||||
<< ", value \"" << make_string() << '"');
|
<< ", value \"" << make_string() << '"');
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -756,7 +756,13 @@ SGPropertyNode::~SGPropertyNode ()
|
|||||||
_removedChildren[i]->_parent = 0;
|
_removedChildren[i]->_parent = 0;
|
||||||
delete _path_cache;
|
delete _path_cache;
|
||||||
clearValue();
|
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.
|
* Remove child by position.
|
||||||
*/
|
*/
|
||||||
@@ -921,8 +943,8 @@ SGPropertyNode::removeChild (int pos, bool keep)
|
|||||||
if (keep) {
|
if (keep) {
|
||||||
_removedChildren.push_back(node);
|
_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->setAttribute(REMOVED, true);
|
||||||
node->clearValue();
|
node->clearValue();
|
||||||
fireChildRemoved(node);
|
fireChildRemoved(node);
|
||||||
@@ -933,7 +955,7 @@ SGPropertyNode::removeChild (int pos, bool keep)
|
|||||||
/**
|
/**
|
||||||
* Remove a child node
|
* Remove a child node
|
||||||
*/
|
*/
|
||||||
SGPropertyNode_ptr
|
SGPropertyNode_ptr
|
||||||
SGPropertyNode::removeChild (const char * name, int index, bool keep)
|
SGPropertyNode::removeChild (const char * name, int index, bool keep)
|
||||||
{
|
{
|
||||||
SGPropertyNode_ptr ret;
|
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 *
|
const char *
|
||||||
SGPropertyNode::getDisplayName (bool simplify) const
|
SGPropertyNode::getDisplayName (bool simplify) const
|
||||||
{
|
{
|
||||||
@@ -2187,23 +2227,31 @@ SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
SGPropertyNode::hash_table::bucket::erase (const char * key)
|
SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
|
||||||
{
|
{
|
||||||
int i;
|
for (int i = 0; i < _length; i++) {
|
||||||
for (i = 0; i < _length; i++) {
|
if (_entries[i]->get_value() == node) {
|
||||||
if (!strcmp(_entries[i]->get_key(), key))
|
delete _entries[i];
|
||||||
break;
|
for (++i; i < _length; i++) {
|
||||||
}
|
_entries[i-1] = _entries[i];
|
||||||
|
}
|
||||||
if (i < _length) {
|
_length--;
|
||||||
for (++i; i < _length; i++) {
|
return true;
|
||||||
_entries[i-1] = _entries[i];
|
|
||||||
}
|
}
|
||||||
_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 ()
|
SGPropertyNode::hash_table::hash_table ()
|
||||||
: _data_length(0),
|
: _data_length(0),
|
||||||
@@ -2213,8 +2261,12 @@ SGPropertyNode::hash_table::hash_table ()
|
|||||||
|
|
||||||
SGPropertyNode::hash_table::~hash_table ()
|
SGPropertyNode::hash_table::~hash_table ()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < _data_length; i++)
|
for (unsigned int i = 0; i < _data_length; i++) {
|
||||||
delete _data[i];
|
if (_data[i]) {
|
||||||
|
_data[i]->clear(this);
|
||||||
|
delete _data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
delete [] _data;
|
delete [] _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2248,17 +2300,17 @@ SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
|
|||||||
}
|
}
|
||||||
entry * e = _data[index]->get_entry(key, true);
|
entry * e = _data[index]->get_entry(key, true);
|
||||||
e->set_value(value);
|
e->set_value(value);
|
||||||
|
value->add_linked_node(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
SGPropertyNode::hash_table::erase (const char * key)
|
SGPropertyNode::hash_table::erase (SGPropertyNode * node)
|
||||||
{
|
{
|
||||||
if (_data_length == 0)
|
for (unsigned int i = 0; i < _data_length; i++)
|
||||||
return;
|
if (_data[i] && _data[i]->erase(node))
|
||||||
unsigned int index = hashcode(key) % _data_length;
|
return true;
|
||||||
if (_data[index] == 0)
|
|
||||||
return;
|
return false;
|
||||||
_data[index]->erase(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
@@ -2280,12 +2332,8 @@ SGPropertyNode::hash_table::hashcode (const char * key)
|
|||||||
|
|
||||||
SGPropertyChangeListener::~SGPropertyChangeListener ()
|
SGPropertyChangeListener::~SGPropertyChangeListener ()
|
||||||
{
|
{
|
||||||
// This will come back and remove
|
for (int i = _properties.size() - 1; i >= 0; i--)
|
||||||
// the current item each time. Is
|
_properties[i]->removeChangeListener(this);
|
||||||
// that OK?
|
|
||||||
vector<SGPropertyNode *>::iterator it;
|
|
||||||
for (it = _properties.begin(); it != _properties.end(); it++)
|
|
||||||
(*it)->removeChangeListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
+25
-4
@@ -1110,6 +1110,12 @@ public:
|
|||||||
void removeChangeListener (SGPropertyChangeListener * listener);
|
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.
|
* Fire a value change event to all listeners.
|
||||||
*/
|
*/
|
||||||
@@ -1183,6 +1189,12 @@ private:
|
|||||||
void trace_write () const;
|
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;
|
class hash_table;
|
||||||
|
|
||||||
int _index;
|
int _index;
|
||||||
@@ -1193,6 +1205,7 @@ private:
|
|||||||
SGPropertyNode * _parent;
|
SGPropertyNode * _parent;
|
||||||
vector<SGPropertyNode_ptr> _children;
|
vector<SGPropertyNode_ptr> _children;
|
||||||
vector<SGPropertyNode_ptr> _removedChildren;
|
vector<SGPropertyNode_ptr> _removedChildren;
|
||||||
|
vector<hash_table *> _linkedNodes;
|
||||||
mutable string _path;
|
mutable string _path;
|
||||||
mutable string _buffer;
|
mutable string _buffer;
|
||||||
hash_table * _path_cache;
|
hash_table * _path_cache;
|
||||||
@@ -1223,9 +1236,16 @@ private:
|
|||||||
vector <SGPropertyChangeListener *> * _listeners;
|
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 {
|
class hash_table {
|
||||||
public:
|
public:
|
||||||
@@ -1243,7 +1263,7 @@ private:
|
|||||||
void set_value (SGPropertyNode * value);
|
void set_value (SGPropertyNode * value);
|
||||||
private:
|
private:
|
||||||
string _key;
|
string _key;
|
||||||
SGSharedPtr<SGPropertyNode> _value;
|
SGSharedPtr<SGPropertyNode> _value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1255,7 +1275,8 @@ private:
|
|||||||
bucket ();
|
bucket ();
|
||||||
~bucket ();
|
~bucket ();
|
||||||
entry * get_entry (const char * key, bool create = false);
|
entry * get_entry (const char * key, bool create = false);
|
||||||
void erase(const char * key);
|
bool erase (SGPropertyNode * node);
|
||||||
|
void clear (hash_table * owner);
|
||||||
private:
|
private:
|
||||||
int _length;
|
int _length;
|
||||||
entry ** _entries;
|
entry ** _entries;
|
||||||
@@ -1267,7 +1288,7 @@ private:
|
|||||||
~hash_table ();
|
~hash_table ();
|
||||||
SGPropertyNode * get (const char * key);
|
SGPropertyNode * get (const char * key);
|
||||||
void put (const char * key, SGPropertyNode * value);
|
void put (const char * key, SGPropertyNode * value);
|
||||||
void erase(const char * key);
|
bool erase (SGPropertyNode * node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int hashcode (const char * key);
|
unsigned int hashcode (const char * key);
|
||||||
|
|||||||
@@ -229,6 +229,21 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
|||||||
} catch (sg_io_exception &e) {
|
} catch (sg_io_exception &e) {
|
||||||
setException(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");
|
const char *type = atts.getValue("type");
|
||||||
@@ -432,11 +447,11 @@ doIndent (ostream &output, int indent)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
writeAtts (ostream &output, const SGPropertyNode * node)
|
writeAtts (ostream &output, const SGPropertyNode * node, bool forceindex)
|
||||||
{
|
{
|
||||||
int index = node->getIndex();
|
int index = node->getIndex();
|
||||||
|
|
||||||
if (index != 0)
|
if (index != 0 || forceindex)
|
||||||
output << " n=\"" << index << '"';
|
output << " n=\"" << index << '"';
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -484,13 +499,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
|
|||||||
|
|
||||||
const string name = node->getName();
|
const string name = node->getName();
|
||||||
int nChildren = node->nChildren();
|
int nChildren = node->nChildren();
|
||||||
|
bool node_has_value = false;
|
||||||
|
|
||||||
// If there is a literal value,
|
// If there is a literal value,
|
||||||
// write it first.
|
// write it first.
|
||||||
if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
|
if (node->hasValue() && (write_all || node->getAttribute(archive_flag))) {
|
||||||
doIndent(output, indent);
|
doIndent(output, indent);
|
||||||
output << '<' << name;
|
output << '<' << name;
|
||||||
writeAtts(output, node);
|
writeAtts(output, node, nChildren != 0);
|
||||||
if (node->isAlias() && node->getAliasTarget() != 0) {
|
if (node->isAlias() && node->getAliasTarget() != 0) {
|
||||||
output << " alias=\"" << node->getAliasTarget()->getPath()
|
output << " alias=\"" << node->getAliasTarget()->getPath()
|
||||||
<< "\"/>" << endl;
|
<< "\"/>" << endl;
|
||||||
@@ -501,13 +517,14 @@ writeNode (ostream &output, const SGPropertyNode * node,
|
|||||||
writeData(output, node->getStringValue());
|
writeData(output, node->getStringValue());
|
||||||
output << "</" << name << '>' << endl;
|
output << "</" << name << '>' << endl;
|
||||||
}
|
}
|
||||||
|
node_has_value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are children, write them next.
|
// If there are children, write them next.
|
||||||
if (nChildren > 0) {
|
if (nChildren > 0) {
|
||||||
doIndent(output, indent);
|
doIndent(output, indent);
|
||||||
output << '<' << name;
|
output << '<' << name;
|
||||||
writeAtts(output, node);
|
writeAtts(output, node, node_has_value);
|
||||||
output << '>' << endl;
|
output << '>' << endl;
|
||||||
for (int i = 0; i < nChildren; i++)
|
for (int i = 0; i < nChildren; i++)
|
||||||
writeNode(output, node->getChild(i), write_all, indent + INDENT_STEP, archive_flag);
|
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,
|
writeProperties (const string &file, const SGPropertyNode * start_node,
|
||||||
bool write_all, SGPropertyNode::Attribute archive_flag)
|
bool write_all, SGPropertyNode::Attribute archive_flag)
|
||||||
{
|
{
|
||||||
|
SGPath path(file.c_str());
|
||||||
|
path.create_dir(0777);
|
||||||
|
|
||||||
ofstream output(file.c_str());
|
ofstream output(file.c_str());
|
||||||
if (output.good()) {
|
if (output.good()) {
|
||||||
writeProperties(output, start_node, write_all, archive_flag);
|
writeProperties(output, start_node, write_all, archive_flag);
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ waytest_LDADD = \
|
|||||||
$(top_builddir)/simgear/math/libsgmath.a \
|
$(top_builddir)/simgear/math/libsgmath.a \
|
||||||
$(top_builddir)/simgear/debug/libsgdebug.a \
|
$(top_builddir)/simgear/debug/libsgdebug.a \
|
||||||
$(top_builddir)/simgear/misc/libsgmisc.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) \
|
$(base_LIBS) \
|
||||||
-lz
|
-lz
|
||||||
|
|
||||||
|
|||||||
+48
-1
@@ -49,7 +49,7 @@ double SGRoute::distance_off_route( double x, double y ) const {
|
|||||||
int n1 = current_wp;
|
int n1 = current_wp;
|
||||||
sgdVec3 p, p0, p1, d;
|
sgdVec3 p, p0, p1, d;
|
||||||
sgdSetVec3( p, x, y, 0.0 );
|
sgdSetVec3( p, x, y, 0.0 );
|
||||||
sgdSetVec3( p0,
|
sgdSetVec3( p0,
|
||||||
route[n0].get_target_lon(), route[n0].get_target_lat(),
|
route[n0].get_target_lon(), route[n0].get_target_lat(),
|
||||||
0.0 );
|
0.0 );
|
||||||
sgdSetVec3( p1,
|
sgdSetVec3( p1,
|
||||||
@@ -68,3 +68,50 @@ double SGRoute::distance_off_route( double x, double y ) const {
|
|||||||
return 0;
|
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;
|
route_list route;
|
||||||
int current_wp;
|
int current_wp;
|
||||||
|
|
||||||
|
void update_distance(int index);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Constructor */
|
/** Constructor */
|
||||||
@@ -70,21 +72,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a waypoint.
|
* Add waypoint (default), or insert waypoint at position n.
|
||||||
* @param wp a waypoint
|
* @param wp a waypoint
|
||||||
*/
|
*/
|
||||||
inline void add_waypoint( const SGWayPoint &wp ) {
|
void add_waypoint( const SGWayPoint &wp, int n = -1 );
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of waypoints (i.e. route length )
|
* Get the number of waypoints (i.e. route length )
|
||||||
* @return route length
|
* @return route length
|
||||||
@@ -146,11 +137,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Delete the front waypoint */
|
/** Delete the front waypoint */
|
||||||
inline void delete_first() {
|
inline void delete_first() { delete_waypoint(0); }
|
||||||
if ( route.size() ) {
|
|
||||||
route.erase( route.begin() );
|
/** 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
|
* Calculate perpendicular distance from the current route segment
|
||||||
|
|||||||
@@ -8,8 +8,20 @@
|
|||||||
|
|
||||||
SG_USING_STD(cout);
|
SG_USING_STD(cout);
|
||||||
SG_USING_STD(endl);
|
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;
|
SGRoute route;
|
||||||
|
|
||||||
route.add_waypoint( SGWayPoint(0, 0, 0, SGWayPoint::CARTESIAN, "Start") );
|
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, 0, 0, SGWayPoint::CARTESIAN, "2") );
|
||||||
route.add_waypoint( SGWayPoint(2, 2, 0, SGWayPoint::CARTESIAN, "3") );
|
route.add_waypoint( SGWayPoint(2, 2, 0, SGWayPoint::CARTESIAN, "3") );
|
||||||
route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") );
|
route.add_waypoint( SGWayPoint(4, 2, 0, SGWayPoint::CARTESIAN, "4") );
|
||||||
|
|
||||||
|
dump_route(route, "Init");
|
||||||
route.set_current( 1 );
|
route.set_current( 1 );
|
||||||
|
|
||||||
cout << "( 0.5, 0 ) = " << route.distance_off_route( 0.5, 0 ) << endl;
|
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, 4 ) = " << route.distance_off_route( 2, 4 ) << endl;
|
||||||
cout << "( 2.5, 4 ) = " << route.distance_off_route( 2.5, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
includedir = @includedir@/scene
|
includedir = @includedir@/scene
|
||||||
|
|
||||||
SUBDIRS = material model sky tgdb
|
SUBDIRS = material model sky tgdb util
|
||||||
|
|
||||||
# lib_LIBRARIES = libsgscene.a
|
# lib_LIBRARIES = libsgscene.a
|
||||||
|
|
||||||
|
|||||||
+134
-41
@@ -37,12 +37,23 @@ SG_USING_STD(map);
|
|||||||
# include <math.h>
|
# include <math.h>
|
||||||
#endif
|
#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/debug/logstream.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
#include <simgear/misc/sgstream.hxx>
|
||||||
|
|
||||||
|
#include <simgear/scene/model/model.hxx>
|
||||||
|
|
||||||
#include "mat.hxx"
|
#include "mat.hxx"
|
||||||
|
|
||||||
|
static map<string, osg::ref_ptr<osg::Texture2D> > _tex_cache;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Constructors and destructor.
|
// Constructors and destructor.
|
||||||
@@ -53,7 +64,7 @@ SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, cons
|
|||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
read_properties( fg_root, props, season );
|
read_properties( fg_root, props, season );
|
||||||
build_ssg_state( false );
|
build_state( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
SGMaterial::SGMaterial( const string &texpath )
|
SGMaterial::SGMaterial( const string &texpath )
|
||||||
@@ -63,13 +74,13 @@ SGMaterial::SGMaterial( const string &texpath )
|
|||||||
_internal_state st( NULL, texpath, false );
|
_internal_state st( NULL, texpath, false );
|
||||||
_status.push_back( st );
|
_status.push_back( st );
|
||||||
|
|
||||||
build_ssg_state( true );
|
build_state( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
SGMaterial::SGMaterial( ssgSimpleState *s )
|
SGMaterial::SGMaterial( osg::StateSet *s )
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
set_ssg_state( s );
|
set_state( s );
|
||||||
}
|
}
|
||||||
|
|
||||||
SGMaterial::~SGMaterial (void)
|
SGMaterial::~SGMaterial (void)
|
||||||
@@ -120,6 +131,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
|||||||
string tname = "unknown.rgb";
|
string tname = "unknown.rgb";
|
||||||
SGPath tpath( fg_root );
|
SGPath tpath( fg_root );
|
||||||
tpath.append("Textures");
|
tpath.append("Textures");
|
||||||
|
tpath.append("Terrain");
|
||||||
tpath.append(tname);
|
tpath.append(tname);
|
||||||
_internal_state st( NULL, tpath.str(), true );
|
_internal_state st( NULL, tpath.str(), true );
|
||||||
_status.push_back( st );
|
_status.push_back( st );
|
||||||
@@ -132,6 +144,13 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props
|
|||||||
mipmap = props->getBoolValue("mipmap", true);
|
mipmap = props->getBoolValue("mipmap", true);
|
||||||
light_coverage = props->getDoubleValue("light-coverage", 0.0);
|
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
|
// Taken from default values as used in ac3d
|
||||||
ambient[0] = props->getDoubleValue("ambient/r", 0.2);
|
ambient[0] = props->getDoubleValue("ambient/r", 0.2);
|
||||||
ambient[1] = props->getDoubleValue("ambient/g", 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");
|
((SGPropertyNode *)props)->getChildren("object-group");
|
||||||
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
|
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
|
||||||
object_groups.push_back(new SGMatModelGroup(object_group_nodes[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;
|
ysize = 0;
|
||||||
wrapu = true;
|
wrapu = true;
|
||||||
wrapv = true;
|
wrapv = true;
|
||||||
|
|
||||||
mipmap = true;
|
mipmap = true;
|
||||||
light_coverage = 0.0;
|
light_coverage = 0.0;
|
||||||
|
|
||||||
|
solid = true;
|
||||||
|
friction_factor = 1;
|
||||||
|
rolling_friction = 0.02;
|
||||||
|
bumpiness = 0;
|
||||||
|
load_resistance = 1e30;
|
||||||
|
|
||||||
shininess = 1.0;
|
shininess = 1.0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
ambient[i] = (i < 3) ? 0.2 : 1.0;
|
ambient[i] = (i < 3) ? 0.2 : 1.0;
|
||||||
@@ -198,16 +233,15 @@ SGMaterial::load_texture ( int n )
|
|||||||
if ( !_status[i].texture_loaded ) {
|
if ( !_status[i].texture_loaded ) {
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
|
SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
|
||||||
<< _status[i].texture_path );
|
<< _status[i].texture_path );
|
||||||
_status[i].state->setTexture(
|
assignTexture(_status[i].state.get(), _status[i].texture_path,
|
||||||
(char *)_status[i].texture_path.c_str(),
|
wrapu, wrapv, mipmap);
|
||||||
wrapu, wrapv, mipmap );
|
|
||||||
_status[i].texture_loaded = true;
|
_status[i].texture_loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssgSimpleState *
|
osg::StateSet *
|
||||||
SGMaterial::get_state (int n) const
|
SGMaterial::get_state (int n) const
|
||||||
{
|
{
|
||||||
if (_status.size() == 0) {
|
if (_status.size() == 0) {
|
||||||
@@ -215,65 +249,124 @@ SGMaterial::get_state (int n) const
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssgSimpleState *st = (n >= 0) ? _status[n].state
|
osg::StateSet *st = (n >= 0) ? _status[n].state.get()
|
||||||
: _status[_current_ptr].state;
|
: _status[_current_ptr].state.get();
|
||||||
((SGMaterial *)this)->_current_ptr += 1;
|
_current_ptr += 1;
|
||||||
if (_current_ptr >= _status.size())
|
if (_current_ptr >= _status.size())
|
||||||
((SGMaterial *)this)->_current_ptr = 0;
|
_current_ptr = 0;
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
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++)
|
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
|
// Set up the textured state
|
||||||
state->setShadeModel( shade_model );
|
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
||||||
state->enable( GL_LIGHTING );
|
shadeModel->setMode(osg::ShadeModel::SMOOTH);
|
||||||
state->enable ( GL_CULL_FACE ) ;
|
stateSet->setAttribute(shadeModel);
|
||||||
state->enable( GL_TEXTURE_2D );
|
|
||||||
state->disable( GL_BLEND );
|
osg::CullFace* cullFace = new osg::CullFace;
|
||||||
state->disable( GL_ALPHA_TEST );
|
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 ) {
|
if ( !defer_tex_load ) {
|
||||||
SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path );
|
SG_LOG(SG_INPUT, SG_INFO, " " << _status[i].texture_path );
|
||||||
state->setTexture( (char *)_status[i].texture_path.c_str(),
|
assignTexture( stateSet, _status[i].texture_path, wrapu, wrapv);
|
||||||
wrapu, wrapv );
|
|
||||||
_status[i].texture_loaded = true;
|
_status[i].texture_loaded = true;
|
||||||
} else {
|
} else {
|
||||||
_status[i].texture_loaded = false;
|
_status[i].texture_loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->enable( GL_COLOR_MATERIAL );
|
osg::Material* material = new osg::Material;
|
||||||
state->setMaterial ( GL_AMBIENT,
|
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||||
ambient[0], ambient[1],
|
material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
|
||||||
ambient[2], ambient[3] ) ;
|
material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
|
||||||
state->setMaterial ( GL_DIFFUSE,
|
material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
|
||||||
diffuse[0], diffuse[1],
|
material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
|
||||||
diffuse[2], diffuse[3] ) ;
|
material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
|
||||||
state->setMaterial ( GL_SPECULAR,
|
stateSet->setAttribute(material);
|
||||||
specular[0], specular[1],
|
|
||||||
specular[2], specular[3] ) ;
|
|
||||||
state->setMaterial ( GL_EMISSION,
|
|
||||||
emission[0], emission[1],
|
|
||||||
emission[2], emission[3] ) ;
|
|
||||||
state->setShininess ( shininess );
|
|
||||||
|
|
||||||
_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 ) );
|
_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 STL_STRING // Standard C++ string library
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <plib/sg.h>
|
#include <simgear/math/SGMath.hxx>
|
||||||
#include <plib/ssg.h>
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/StateSet>
|
||||||
|
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/structure/ssgSharedPtr.hxx>
|
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||||
|
|
||||||
#include "matmodel.hxx"
|
#include "matmodel.hxx"
|
||||||
|
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
SG_USING_STD(vector);
|
SG_USING_STD(vector);
|
||||||
|
SG_USING_STD(map);
|
||||||
|
|
||||||
|
|
||||||
|
class SGMaterialGlyph;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A material in the scene graph.
|
* 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,
|
* This constructor allows the application to create a custom,
|
||||||
* low-level state for the scene graph and wrap a material around
|
* low-level state for the scene graph and wrap a material around
|
||||||
* it. Note: the pointer ownership is transferred to the material.
|
* 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.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
virtual ~SGMaterial( void );
|
~SGMaterial( void );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -113,31 +119,30 @@ public:
|
|||||||
* @return true if the texture loaded, false if it was loaded
|
* @return true if the texture loaded, false if it was loaded
|
||||||
* already.
|
* already.
|
||||||
*/
|
*/
|
||||||
virtual bool load_texture (int n = -1);
|
bool load_texture (int n = -1);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the textured state.
|
* 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.
|
* 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.
|
* 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.
|
* 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.
|
* @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.
|
* 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.
|
* 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 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:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
@@ -173,14 +231,14 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* Initialization method, invoked by all public constructors.
|
* Initialization method, invoked by all public constructors.
|
||||||
*/
|
*/
|
||||||
virtual void init();
|
void init();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct _internal_state {
|
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) {}
|
: state(s), texture_path(t), texture_loaded(l) {}
|
||||||
ssgSharedPtr<ssgSimpleState> state;
|
osg::ref_ptr<osg::StateSet> state;
|
||||||
string texture_path;
|
string texture_path;
|
||||||
bool texture_loaded;
|
bool texture_loaded;
|
||||||
};
|
};
|
||||||
@@ -196,7 +254,7 @@ private:
|
|||||||
vector<_internal_state> _status;
|
vector<_internal_state> _status;
|
||||||
|
|
||||||
// Round-robin counter
|
// Round-robin counter
|
||||||
unsigned int _current_ptr;
|
mutable unsigned int _current_ptr;
|
||||||
|
|
||||||
// texture size
|
// texture size
|
||||||
double xsize, ysize;
|
double xsize, ysize;
|
||||||
@@ -210,12 +268,33 @@ private:
|
|||||||
// coverage of night lighting.
|
// coverage of night lighting.
|
||||||
double light_coverage;
|
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
|
// material properties
|
||||||
sgVec4 ambient, diffuse, specular, emission;
|
SGVec4f ambient, diffuse, specular, emission;
|
||||||
double shininess;
|
double shininess;
|
||||||
|
|
||||||
|
// the list of names for this material. May be empty.
|
||||||
|
vector<string> _names;
|
||||||
|
|
||||||
vector<SGSharedPtr<SGMatModelGroup> > object_groups;
|
vector<SGSharedPtr<SGMatModelGroup> > object_groups;
|
||||||
|
|
||||||
|
// taxiway-/runway-sign texture elements
|
||||||
|
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Internal constructors and methods.
|
// Internal constructors and methods.
|
||||||
@@ -224,10 +303,41 @@ private:
|
|||||||
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
|
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
|
||||||
|
|
||||||
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
|
void read_properties( const string &fg_root, const SGPropertyNode *props, const char *season );
|
||||||
void build_ssg_state( bool defer_tex_load );
|
void build_state( bool defer_tex_load );
|
||||||
void set_ssg_state( ssgSimpleState *s );
|
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
|
#endif // _SG_MAT_HXX
|
||||||
|
|||||||
@@ -42,10 +42,24 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include STL_STRING
|
#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/debug/logstream.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
#include <simgear/misc/sgstream.hxx>
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
|
#include <simgear/scene/tgdb/userdata.hxx>
|
||||||
|
|
||||||
#include "mat.hxx"
|
#include "mat.hxx"
|
||||||
|
|
||||||
@@ -54,126 +68,10 @@
|
|||||||
SG_USING_NAMESPACE(std);
|
SG_USING_NAMESPACE(std);
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SGMaterialLib::SGMaterialLib ( void ) {
|
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
|
// Load a library of material properties
|
||||||
bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
|
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++) {
|
for (int i = 0; i < nMaterials; i++) {
|
||||||
const SGPropertyNode * node = materials.getChild(i);
|
const SGPropertyNode * node = materials.getChild(i);
|
||||||
if (!strcmp(node->getName(), "material")) {
|
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");
|
vector<SGPropertyNode_ptr>names = node->getChildren("name");
|
||||||
for ( unsigned int j = 0; j < names.size(); j++ ) {
|
for ( unsigned int j = 0; j < names.size(); j++ ) {
|
||||||
string name = names[j]->getStringValue();
|
string name = names[j]->getStringValue();
|
||||||
// cerr << "Material " << name << endl;
|
// cerr << "Material " << name << endl;
|
||||||
matlib[name] = m;
|
matlib[name] = m;
|
||||||
|
m->add_name(name);
|
||||||
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
|
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material "
|
||||||
<< names[j]->getStringValue() );
|
<< 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,18 +133,20 @@ bool SGMaterialLib::add_item ( const string &mat_name, const string &full_path )
|
|||||||
<< mat_name << " (" << full_path << ")");
|
<< mat_name << " (" << full_path << ")");
|
||||||
|
|
||||||
matlib[mat_name] = new SGMaterial( full_path );
|
matlib[mat_name] = new SGMaterial( full_path );
|
||||||
|
matlib[mat_name]->add_name(mat_name);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Load a library of material properties
|
// 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] = new SGMaterial( state );
|
||||||
|
matlib[mat_name]->add_name(mat_name);
|
||||||
|
|
||||||
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
|
SG_LOG( SG_TERRAIN, SG_INFO, " Loading material given a premade "
|
||||||
<< "ssgSimpleState = " << mat_name );
|
<< "osg::StateSet = " << mat_name );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -538,3 +182,21 @@ void SGMaterialLib::load_next_deferred() {
|
|||||||
return;
|
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