1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

Compare commits

..

29 Commits

Author SHA1 Message Date
mzernova
832a6f4412 0031279: Visualization, TKOpenGl - environment background is misplaced within Ray-Tracing
Fixed problem with misplacing background texture in Ray-Tracing.

An environment background is always drawn using a perspective matrix.
2020-06-26 15:07:40 +03:00
iko
4e8371cb1f 0031370: Documentation - provide information about PBR implementation
PBR documentation (math) has been added as developer guide.
2020-06-25 19:25:52 +03:00
kgv
d22962e4e0 0031621: Draw Harness - handle navigation keys
AIS_ViewController::handleNavigationKeys() - added an interface for processing navigation keys.
ViewerTest_EventManager now maps WASD+Arrows navigation keys.
Axonometric view hotkey A has been replaced by Backspace.
Shaded/Wireframe are now mapped with hotkeys W+Ctrl/S+Ctrl.
Hotkey D (reset view to undefined default state) has been removed.
2020-06-25 19:24:58 +03:00
mzernova
2ff1d580f1 0031412: Visualization - entity behind is returned as topmost at the edges
SelectMgr_RectangularFrustum now handles degenerated triangle as a segment or a point.
Triangle orthogonal to view direction is now handled as a segment.
myViewRayDir field is now defined as normalized vector to avoid confusing math.

For the case when the segment and myViewRayDir are almost parallel,
the segmentSegmentDistance function may set the depth to zero, although this will not
be the correct value, therefore it is better to pass a segment that will not
be parallel to myViewRayDir as an argument to the function.

vpoint command has been extended by arguments -2d and -nosel
for displaying picking mouse position as on-screen point in pixels.
Fixed double-binding-map error in case of displaying point with already used name.

bugs/vis/bug31412: test case added.
2020-06-25 19:09:04 +03:00
kgv
64f128c111 0031622: Samples - update MFC Animation sample with proper frame updates
Animation sample has been updated to:
- use reuse AIS_ViewController for general viewer manipulations;
- update animation using elapsed time;
- do not block camera manipilations;
- get rid of redundant controls.
2020-06-25 19:09:03 +03:00
kgv
08b7a39f75 0030939: Draw Harness, ViewerTest - AIS_ViewCube animation does not work on Linux and macOS
ViewerTest_EventManager::handleViewRedraw() now starts ViewerTest_ContinuousRedrawer
working thread to workaround Tcl event loop invalidation issue.
2020-06-25 19:09:02 +03:00
kgv
ceddb5ca9a 0031620: Samples - update Android JNI sample to use AIS_ViewController
Multi-touch input is now redirected to AIS_ViewController.
GLSurfaceView.RENDERMODE_WHEN_DIRTY is now used by 3D Viewer.
AIS_ViewCube is now displayed instead of trihedron.
2020-06-22 11:53:57 +03:00
kgv
bbe85f2b40 0031619: Samples - update JNI sample to use Android Studio
Project structure and project files have been updated to use Android Studio 4.0, gradle and CMake.
Redundant OcctJni_Window has been replaced by Aspect_NeutralWindow.
SD Card permissions are not dynamically requested for compatibility with Android API level 26+.
2020-06-22 09:19:06 +03:00
mpv
ef779ae0da 0031075: Application Framework - reading STEP file into TDocStd_Document leads to memory leaks
In the TDocStd_Owner keep simple pointer to TDocStd_Document instead of Handle. This causes automatic destruction of the document without explicit call of Close.
In Standard_Type added a static variable theType that initializes theRegistry map earlier. Otherwise exit from Draw interpreter crashes in many test-cases because not-closed transactions are aborted on document handle release from Draw theVariables map.

Corrected method for test OCC159bug due to the fact that Owner does not add a ref count now
Close the document in the end of bugs xde bug22776 otherwise double remove of visualization objects (on library exit and on visualization attributes remove from the document) causes crash on exit from draw
Added a new test bugs caf bug31075
2020-06-19 19:08:46 +03:00
ifv
003c363cf4 0031615: Coding - New warnings after integration fix for 0031552 2020-06-18 20:00:39 +03:00
ifv
dccf867561 0031602: [Regression vs 7.0.0] Modeling Algorithms - Invalid result of boolean operation
IntPatch/IntPatch_ImpImpIntersection_4.gxx : adding tolerance in comparison surface range and surface period
bug31602: test case added
2020-06-18 19:59:49 +03:00
ifv
5d904c3454 0031611: Modeling Algorithms - BRepOffsetAPI_NormalProjection - can't build wire in 720 but it was possible in 691
BRepLib_MakeWire.cxx:
in method BRepLib_BndBoxVertexSelector::Accept() accepting tolerance criterion is changed

BRepLib_MakeWire.hxx:
correctionof class field name

bug31611: test case added
2020-06-18 19:57:46 +03:00
mzernova
9a31c01064 0030922: Visualization - OpenGl_Text wrong local transformation if text has not own attach point
bugs/vis/bug30922: test case added
2020-06-16 14:29:41 +03:00
kgv
32b723d5c6 0031606: Configuration, CMake - build fails with Android NDK + CLang compiler + MinGW Makefiles
CLang is now checked before MINGW within occt_defs_flags.cmake.
Added "-Wl,-s" linker flag when using CLang for stripping symbols consistently to GCC builds.
2020-06-13 17:17:53 +03:00
jgv
36cc58f85d 0031485: Data Exchange - Export STEP in nonmanifold mode looses all faces except one
Small correction in STEPControl_ActorWrite::TransferCompound - take into account the case when a subshape has type TopAbs_FACE.
2020-06-10 20:41:40 +03:00
emv
09543c2d99 0031587: Modeling Data - add BRepTools::RemoveInternals() removing internal sub-shapes from the shape 2020-06-09 20:01:06 +03:00
kgv
a7400019ce 0031599: Visualization - when using AIS_Manipulator, the scene rotates at the same time
AIS_ViewController::HandleViewEvents() - reverted order of handleMoveTo() and handleCameraActions() events.
2020-06-09 19:53:08 +03:00
akaftasev
1fc1a207b0 0031504: Data Exchange - Wrong output of progress indicator when writing to stl
Added new condition for first indicated element at Draw_ProgressIndicator::Show(),
because it’s more logical that at start progress starts at 0
Changed usage of Next() to Next(step) for increment progress to IND_THRESHOLD in RWStl::writeASCII() and RWStl::writeBinary()
Changed condition for continuation of writing and add interrupt to this function
Added possibility to use Progress indicator in writestl
Changed paremeter in constructor Message_ProgressSentry aPS() IND_THRESHOLD to 1
Changed test
2020-06-09 19:53:08 +03:00
kgv
59ec2ccec9 0031596: Visualization, OpenGl_Context - take GL_OES_texture_float extension into account for arbTexFloat flag 2020-06-09 19:53:07 +03:00
kgv
d4cefcc0da 0031477: Visualization, TKOpenGl - fetch/wrap getBufferSubData() function from WebGL 2.0
Added OpenGl_Context::GetBufferSubData() implementing getBufferSubData() based on capabilities of various APIs.
Added OpenGl_VertexBuffer::GetSubData() similar to OpenGl_VertexBuffer::SubData().
2020-05-29 19:40:57 +03:00
kgv
872f98d9ef 0031583: Visualization, OpenGl_Context - load OpenGL ES 3.0 functions
OpenGl_Context now retrieves complete functions sets of OpenGL ES 3.0, 3.1 and 3.2.
2020-05-28 10:24:35 +03:00
vsv
2ba1172b73 0031573: Visualization - Do not show seam edge for shading presentation with boundary edges in VTK 2020-05-28 10:22:54 +03:00
kgv
e4e3254a35 0031580: Visualization, TKOpenGl - cubemap initialization error on OpenGL ES 2.0
OpenGl_Texture::InitCubeMap() now avoids using sized internal format in case of GLES2.
OpenGl_Sampler::applySamplerParams() now checks OpenGL version before setting GL_TEXTURE_WRAP_R.
2020-05-28 10:21:03 +03:00
mkrylova
04c5a696e4 0029917: Foundation Classes - OSD_FileNode AccessMoment and CreationMoment return the same date on Windows
fAccess in CreationMoment() function for Windows has been modified from TRUE to FALSE
2020-05-28 10:18:56 +03:00
ika
ae58f70718 0031568: Data Exchange - invalid model produced after STEP import
Add protection against reference to reference in STEP import.
2020-05-22 19:32:21 +03:00
kgv
faff37677c 0031478: Visualization, TKOpenGl - allow uploading Cubemap in compressed DDS format when supported by GPU
Graphic3d_TextureRoot::GetCompressedImage() - added new interface for fetching compressed texture image.
Default implementation detects DDS image files using Image_DDSParser parser.

Graphic3d_TextureRoot::GetImage() has been extended with new parameter
- the list of image formats supported by OpenGL driver.
Graphic3d_TextureRoot::convertToCompatible() implicitly converts
BGRA image to RGBA on OpenGL ES, which normally does not support BGR formats.

OpenGl_Caps::isTopDownTextureUV - new property defines how application defines
UV texture coordinates in primitive arrays.
OpenGl_Context::SetTextureMatrix() compares this flag with OpenGl_Texture::IsTopDown()
and automatically flips V coordinate in case of mismatch.

OpenGl_Texture now holds exact number of mipmap levels
instead of Boolean flag indicating that they are defined.
This allows loading DDS files with incomplete mipmap level set
by setting GL_TEXTURE_MAX_LEVEL to appropriate value instead of default 1000
(causing black textures in case if mipmap levels are not defined till 1x1).

Fixed order of texture coordinates transformation within GLSL program to match FFP matrix:
Rotate -> Translate -> Scale (previously Rotation was applied afterwards).
2020-05-22 11:08:34 +03:00
Igor Khozhanov
691711cd3e 0031550: Data Exchange, STEP Import - surface transparency is ignored (SURFACE_STYLE_TRANSPARENT)
Implemented reading and writing transparency to/from step files
2020-05-22 11:07:37 +03:00
ifv
8189cc72d0 0028229: BRep_Builder::Transfert must not raise exception if the input edge is Locked
BRep/BRep_Builder.cxx : raising exception is removed
2020-05-22 11:07:36 +03:00
jgv
c6f14a5213 0031558: BRepOffsetAPI_MakeFilling algorithm makes turned inside out face
1. Modification in method BRepFill_Filling::Build - correction of building the wire.
2. Create new subgroup "filling" in the group "bugs".
2020-05-22 11:07:35 +03:00
307 changed files with 8717 additions and 4484 deletions

View File

@@ -111,7 +111,18 @@ elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMP
endif()
endif()
if(MINGW)
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
if (APPLE)
# CLang can be used with both libstdc++ and libc++, however on OS X libstdc++ is outdated.
set (CMAKE_CXX_FLAGS "-std=c++0x -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
elseif(NOT WIN32)
# CLang for Windows (at least CLang 8.0 distributed with VS 2019)
# does not support option "-std=c++0x"
set (CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
endif()
# Optimize size of binaries
set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-s ${CMAKE_SHARED_LINKER_FLAGS}")
elseif(MINGW)
# Set default release optimization option to O2 instead of O3, since in
# some OCCT related examples, this gives significantly smaller binaries
# at comparable performace with MinGW-w64.
@@ -122,25 +133,19 @@ if(MINGW)
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
endif()
set (CMAKE_CXX_FLAGS "-std=gnu++0x ${CMAKE_CXX_FLAGS}")
add_definitions(-D_WIN32_WINNT=0x0501)
# workaround bugs in mingw with vtable export
set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--export-all-symbols")
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang")
if (APPLE)
# CLang can be used with both libstdc++ and libc++, however on OS X libstdc++ is outdated.
set (CMAKE_CXX_FLAGS "-std=c++0x -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
elseif(NOT WIN32)
# CLang for Windows (at least CLang 8.0 distributed with VS 2019)
# does not support option "-std=c++0x"
set (CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
endif()
elseif (DEFINED CMAKE_COMPILER_IS_GNUCXX)
set (CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
endif()
# Optimize size of binaries
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR MINGW)
# Require C++11
set (CMAKE_CXX_FLAGS "-std=gnu++0x ${CMAKE_CXX_FLAGS}")
# Optimize size of binaries
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
elseif (DEFINED CMAKE_COMPILER_IS_GNUCXX)
# Require C++11
set (CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
# Optimize size of binaries
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
endif()

View File

@@ -45,6 +45,7 @@ dev_guides/git_guide/git_guide.md
dev_guides/tests/tests.md
dev_guides/debug/debug.md
dev_guides/upgrade/upgrade.md
dev_guides/visualization/pbr_math.md
dev_guides/building/building.md
dev_guides/building/3rdparty/3rdparty_windows.md

View File

@@ -26,5 +26,6 @@ dev_guides/contribution/coding_rules.md
dev_guides/git_guide/git_guide.md
dev_guides/tests/tests.md
dev_guides/upgrade/upgrade.md
dev_guides/visualization/pbr_math.md
tutorial/tutorial.md

View File

@@ -11,6 +11,10 @@ The following documents provide information on OCCT building, development and te
* @subpage occt_dev_guides__tests "Automatic Testing system"
* @subpage occt_dev_guides__debug "Debugging tools and hints"
The following documents provide information on OCCT algorithms background:
* @subpage occt_dev_guides__pbr_math "Physically-based Rendering math (PBR for rasterization)"
The following guide provides information relevant to upgrading applications developed with previous versions of OCCT, to recent one:
* @subpage occt_dev_guides__upgrade "Upgrade from previous OCCT versions"

View File

@@ -1979,3 +1979,9 @@ After the change, extended variant:
Previously, sub-classes of *Message_Printer* have to provide a triplet of *Message_Printer::Send()* methods accepting different string representations: TCollection_AsciiString, TCollection_ExtendedString and Standard_CString.
*Message_Printer* interface has been changed, so that sub-classes now have to implement only single method *Message_Printer::send()* accepting TCollection_AsciiString argument and having no Endl flag, which has been removed.
Old three Message_Printer::Send() methods remain defined virtual with unused last argument and redirecting to new send() method by default.
@subsection upgrade_750_draw_hotkeys Draw Harness hotkeys
Draw Harness hotkeys **W** (Wireframe) and **S** (Shaded) have been re-mapped to **Ctrl+W** and **Ctrl+S**.
Hotkey **A** has been remapped to **Backspace**.
Hotkeys WASD and Arrays are now mapped for walk-through navigation in 3D Viewer.

View File

@@ -0,0 +1,777 @@
PBR math (rasterization) {#occt_dev_guides__pbr_math}
========================
@tableofcontents
# Preface
**Empirical** illumination models like **Phong reflection model** have been used in real-time graphics for a long time due to their simplicity, convincing look and affordable performance.
Before programmable pipeline has been introduced, graphics cards implemented Gouraud shading as part of fixed-function Transformation & Lighting (T&L) hardware blocks.
Nowadays, however, numerous trade-offs of this simplicity (like lighting partially baked into object material properties and others) pushed developers to **Physically-Based Rendering** (**PBR**) illumination models.
PBR models try to fit surface shading formulas into constrains of physical laws of light propagation / absorption / reflection - hence, called "physically-based".
There are two main categories of PBR illumination:
1. Non-real-time renderer (cinematic).
2. Real-time renderer.
The main objective of cinematic renderer is uncompromised quality, so that it relies on ray-tracing (path-tracing) rendering pipeline.
Although performance of current graphics hardware does not make it possible using computationally-intensive path-tracing renderer in real-time graphics, it can be used in interactive fashion.
"Physically-based" does not necessarily mean physically-correct/precise.
The main objective of real-time PBR renderer is to be fast enough even on low-end graphics hardware.
So that in contrast, it hardly relies on rasterization rendering pipeline, various approximations and tricks making it applicable in real-time, while looking good enough and preserving some physical properties.
OCCT 3D Viewer provides both kinds of PBR renderers, and although they share some details in common, this article is devoted to real-time PBR metallic-roughness illumination model.
This article describes the math underneath PBR shading in OCCT 3D Viewer and its GLSL programs.
However, this article does not clarifies related high-level APIs nor PBR material creation pipelines, as this is another topic.
# Notation
| | | |
|-:|:-|:-|
| \f$n\f$ | normal (on surface) | \f$\|n\|=1\f$ |
| \f$v\f$ | view direction | \f$\|v\|=1\f$ |
| \f$l\f$ | light | \f$\|l\| = 1\f$ |
| \f$h=\frac{v+l}{\|v + l\|}\f$ | half vector | |
| \f$m\f$ | metallic factor | \f$[0, 1]\f$ |
| \f$r\f$ | roughness factor | \f$[0, 1]\f$ |
| \f$IOR\f$ | index of refraction | \f$[1, 3]\f$ |
| \f$c\f$ | albedo color | \f$(R, G, B)\f$ |
\f$\cos\theta_l=(n \cdot l)\f$
\f$\cos\theta_v=(n \cdot v)\f$
\f$\cos\theta_h=(n \cdot h)\f$
\f$\cos\theta_{vh}=(v \cdot h)\f$
# Illumination model
The main goal of illumination model is to calculate outgoing light radiance \f$L_o\f$ along the certain direction.
The starting point of calculation might be the view direction \f$v\f$ aimed from point on surface (or in more general case just in space) to viewer position.
Considering the point on opaque surface with normal \f$n\f$ the main equation of illumination can be defined as:
\f[L_o=\int\limits_H f(v, l) L_i(l) \cos\theta_l\, \mathrm{d}l\f]
Where \f$L_i(l)\f$ is light radiance coming from \f$l\f$ direction, \f$f(v,l)\f$ is **Bidirectional Reflectance Distribution Function** (**BRDF**) and \f$H\f$ is hemisphere which is oriented regarding to the surface normal \f$n\f$.
Opaqueness of the surface mentioned earlier is important because in that case hemisphere is enough.
More general model will require to consider directions all around a whole sphere and is not observed in this paper.
\f$\cos\theta_l\f$ factor appearing is caused by affection of surface area and light direction mutual orientation to the amount of radiance coming to this area.
This is mainly due to geometric laws. The rest part of integral is the key of the whole illumination model.
BRDF defines it's complexity and optical properties of material.
It has to model all light and material interactions and also has to satisfy some following criteria in order to be physical correct:
* Positivity: \f$f(v,l) \geq 0\f$
* Helmholtz reciprocity: \f$f(v,l) = f(l, v)\f$ (follows from 2<sup>nd</sup> Law of Thermodynamics)
* Energy conservation: \f$\displaystyle \forall v \, \int\limits_H f(v,l) \cos\theta_l \, \mathrm{d}l = 1\f$ (in order not to reflect more light than came)
It is worth to be mentioned that \f$f(v,l)\f$ depends on \f$n\f$ also but it is omitted to simplify notation. BRDF is usually split into two parts:
\f[f(v,l) = f_d(v,l)+f_s(v, l)\f]
Where \f$f_s(v, l)\f$ (specular BRDF) models reflection light interaction on surface and \f$f_d(v,l)\f$ (diffuse BRDF) models other processes happening depth in material (subsurface scattering for example).
So that illumination equation might be rewritten as:
\f[L_o=\int\limits_H (f_d(v,l)+f_s(v, l)) L_i(l) \cos\theta_l\, \mathrm{d}l\f]
PBR theory is based on **Cook-Torrance specular BRDF**. It imagines surface as set of perfectly reflected micro faces distributed on area in different ways which is pretty good model approximation of real world materials.
If this area is small enough not to be able to recognize separate micro surfaces the results becomes a sort of averaging or mixing of every micro plane illumination contribution.
In that level it allows to work with micro faces in statistical manner manipulating only probabilities distributions of micro surfaces parameters such as normals, height, pattern, orientation etc.
In computer graphics pixels are units of images and it usually covers a relatively large areas of surfaces so that micro planes can be considered to be unrecognizable.
Going back to the BRDF the Cook-Torrance approach has the following expression:
\f[f_s(v,l)=\frac{DGF}{4\cos\theta_l\cos\theta_v}\f]
Three parts presented in nominator have its own meaning but can have different implementation with various levels of complexity and physical accuracy.
In that paper only one certain implementation is used. The \f$D\f$ component is responsible for **micro faces normals distribution**.
It is the main instrument that controls reflection's shape and strength according to **roughness** \f$r\f$ parameter.
The implementation with good visual results is **Trowbridge-Reitz GGX** approach used in Disney's RenderMan and Unreal Engine:
\f[D=\frac{\alpha^2}{\pi(\cos^2\theta_h(\alpha^2-1) + 1)^2}\f]
Where \f$\alpha = r^2\f$. This square in needed only for smoother roughness parameter control.
Without it the visual appearance of surface becomes rough too quickly during the parameter's increasing.
The second \f$G\f$ component is called **geometric shadowing** or attenuation factor.
The point is that micro surfaces form kind of terrain and can cast shadows over each other especially on extreme viewing angles.
**Schlick's model** has been chosen as implementation:
\f[\displaystyle G=\frac{\cos\theta_l \cos\theta_v}{(\cos\theta_l(1-k)+k)(\cos\theta_v(1-k)+k)}\f]
Where \f$k=\frac{\alpha}{2}\f$, which means \f$k=\frac{r^2}{2}\f$ in terms of this paper.
But \f$G\f$ depends on many factors so that it's approximations has float nature and can be modified a little bit in some cases in order to get more pleasant visual results.
One of this modification will be described later in following chapters.
The last component \f$F\f$ shows **how much light is reflected from surface** and is called **Fresnel's factor**.
The rest amount of radiance might be absorbed or refracted by material.
The most accurate expression of it is pretty complicate for calculation so that there is a variety of approximations.
The good one with less computation efforts is **Schlick's implementation**:
\f[F=F_0+(1-F_0)(1-\cos\theta_{vh})^5\f]
Here \f$F_0\f$ is material's response coefficient at normal incidence (zero angle).
Fresnel's factor has to be calculated differently for metals and dielectric/non-metals, but PBR theory tries to come up with universal formula for all types of material.
In order to do that it is needed to be noticed that Schlick's approximation is applicable only to non-conductors and in that case \f$F_0 = F_{dielectric} = \left(\frac{1-IOR}{1+IOR}\right)^2\f$.
**Index of Refraction** \f$IOR\f$ shows the proportion between light speed in vacuum (or even in air) and in material.
The reference value of \f$IOR\f$ for plastic is **1.5**, and this value can be considered as default for all unknown dielectrics.
In practice this parameter controls reflectance ability of material.
Also it should be remembered that this approximation produces poor results with large \f$IOR\f$ values so that it is recommended to be kept in range of \f$[1, 3]\f$ in order to get plausible Fresnel's factor.
This formula might be further propagated onto metals by using \f$F_0\f$ measured specifically for certain metal.
It can be considered as some kind of a 'color' of metal and can be stored as albedo parameter \f$c\f$.
And the final step of defining Fresnel's factor formula is mixing all this \f$F_0\f$ using metallic parameter \f$m\f$ (**metalness**):
\f[F_0 = F_{dielectric}(1-m)+cm\f]
For pure dielectrics with \f$m=0\f$ exactly Schlick's approximation will be used.
For pure metals with \f$m=1\f$ it will be a little inaccurate but the same formula with measured \f$F_0\f$ values.
Everything else for \f$m \in (0, 1)\f$ is not physically correct and it is recommended to keep \f$m\f$ exactly 1 or 0.
Intermediate values may represent mixed areas for smooth transition between materials - like partially rusted metal (rust is mostly dielectric).
Also it might be useful when parameters are read from textures with filtering and smoothing.
BRDF described above has one important trait making computations easier called **isotropy**.
Isotropy in this case means independence from rotation about normal resulting from supposition of uniform micro faces distribution at any direction along a surface.
It allows to simplify random samples generation during Monte-Carlo integrals calculation and reduce dimensions of some lookup tables, which will be discussed in following chapters.
Of course, isotropic materials form only subset of all real world's materials, but this subset covers majority of cases.
There are special models considering special anisotropic traits of surfaces like a grinding of metal or other with dependency on rotation about normal;
these models require special calculation tricks and additional parameters and are out of scope of this paper.
The only thing left to do is to define \f$f_d(v,l)\f$.
This part is responsible for processes happening in depth of material.
First of all the amount of input light radiance participating in these processes is needed to be calculated.
And it exactly can be realized from already known Fresnel's factor \f$F\f$ showing amount of reflected light but in negative term in this case in order to get the radiance left after reflection:
\f[1-F\f]
This part of ingoing light is assumed to be refracted in depth of surface and variety of events may happen there.
A sequence of absorptions, reflections and reemissions more or less leads to light's subsurface scattering.
Some part of this scattered light can go back outside but in modified form and in pretty unpredictable directions and positions.
For opaque materials this part is noticeable and forms it's own color.
If subsurface's paths of light are small enough and points of output are distributed locally around the input point it's possible to work in statistical way similar to the micro faces.
This assumption covers a big amount of real world opaque materials.
Other materials like skin, milk etc. with noticeable effect of subsurface scattering usually presented in form of partial translucency and some kind of self emission
have more widely distributed output points and require more accurate and complicate ways of modeling with maybe some theory and techniques from volumetric rendering.
The simple but visually enough assuming for statistically driven type of materials is just the same radiance for any direction. It results to **Lambertian's BRDF**:
\f[\frac{c}{\pi}\f]
Where \f$\pi\f$ is normalization coefficient in order to meet BRDF's criteria and \f$c\f$ is material's own color formed by adventures of light under surface.
There is one detail about light interaction bringing some physicality to the model, and that is an absence of this diffuse component in metals.
Metals reflect main part of light and the rest of it is absorbed being transformed into other form (mostly heat).
That is the main visual difference between metallic and non-metallic materials realizing of which brings model to higher level of quality in compare to older non-physical models.
So that all parts described above can be combined into united diffuse BRDF:
\f[f_d(v,l) = (1-F)(1-m)\frac{c}{\pi}\f]
\f$m\f$ is recommended to be exactly 1 or 0 but all values between can represent transition areas, as mentioned before.
In this chapter one possible implementation of illumination model reflecting main PBR principles has been defined.
The next step is using of it in practice.
# Practical application
It's time to apply deduced illumination model in practice.
And the first step of it is separation of **direction based light sources** from illumination integral.
Directional nature of such light sources means possibility to calculate it's influence to point of surface using only one direction and its intensity.
Usually sources of this type do not have physical size and are represented only by position in space (for point or spot lights) or by direction itself (direction light imagined to be too far point sources like sun).
This is just a kind of abstraction, while real world light emitters have noticeably sizes.
But sources with realistic form and size cannot be presented in discrete term and require continuous integrals calculations or special approximations in order to be accurately injected to the model.
In most cases direct based light sources in form of emitting points in space or just certain directions are good approximations and are enough for beginning.
Having finite discrete amount of it in scene and considering only single direction from every of these lights, the integral is transformed just to the sum:
\f[L_{direct} = \sum_{j=1}^M f(v, l_j) L_i^{direct}(l_j) \cos\theta_{l_j}\f]
Where \f$M\f$ is a number of sources, \f$l_j\f$ is a direction and \f$L_i^{direct}\f$ is an intensity related to this direction.
\f$direct\f$ label means that illumination has been computed directly from sources.
The BRDF can be used directly without any calculation problems.
The only exception might be \f$k\f$ in \f$G\f$ factor - it is recommended to be equal \f$\frac{(r+1)^2}{8}\f$ in order to get more pleasant results (that is modification mentioned in previous chapter).
And actually it is enough to finally see something.
There will be correct visualization with assumption of complete dark environment and absence of other points influence.
It is called **local illumination**. Based on this name there is also a global or **indirect illumination** and that is the rest of integral:
\f[L_{indirect} = \int\limits_H f(v, l) L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l\f]
It includes influence of light reflected or scattered from other points and environment's contribution.
It's impossible to achieve photorealistic results without this component, but is is also very difficult to compute.
While the cross point light interaction cannot be calculated in a simple way (especially in real time rendering), the environment illumination has some options to be realized via precomputational work before visualization.
But right now lets summarize the practical application of illumination model.
At this moment the output radiance is represented as:
\f[L_o = L_{direct} + L_{indirect}\f]
Where \f$L_{direct}\f$ is direction based light sources contribution which can be directly computed just applying bare formulas.
It is enough to get some results in terms of local illumination but without \f$L_{indirect}\f$ component image will not be looked lifelike.
\f$L_{indirect}\f$ is not trivial thing for calculation and that is stumbling block for real time rendering applications.
But it can be relatively easy implemented in case of environment illumination via some precomputational work about which will be told in details in following chapters.
# Image based lighting
The next goal after \f$L_{direct}\f$ calculation is to find \f$L_{indirect}\f$.
And it would be easier if \f$L_i^{indirect}(l)\f$ was known for every \f$l\f$.
That is the main assumption of **image based lightning** (**IBL**).
In practice, it can be achieved using environment image map, which is a special image representing illumination from all possible directions.
This image might be a photo capturing a real world environment (spherical 360 degrees panoramas) or generated image baking the 3D scene itself, including in that case reflections of other objects.
Environment image might be packed in different ways - **cube maps** and equirectangular maps are the most commonly used.
Anyway, it allows \f$L_i^{indirect}(l)\f$ to be defined for every \f$l\f$ and its practical implementation in form of images gives name for this approach.
Lets back to indirect illumination integral:
\f[L_{indirect} = \int\limits_H f(v, l) L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l\f]
Substituting the BRDF by its expression allows to split indirect illumination into diffuse and specular components:
\f[L_{indirect} = \int\limits_H f_d(v,l)L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l + \int\limits_H f_s(v,l)L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l = \f]
\f[= (1-m)\frac{c}{\pi}\int\limits_H (1-F)L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l + \frac{1}{4}\int\limits_H \frac{DFG}{\cos\theta_l \cos\theta_v}L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l\f]
This splitting seems not to lead to simplicity of calculation but these two parts will be computed in slightly different ways in future.
Lets write down this separately:
\f[L_{indirect}^d = (1-m)\frac{c}{\pi}\int\limits_H (1-F)L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l\f]
\f[L_{indirect}^s = \frac{1}{4}\int\limits_H \frac{DFG}{\cos\theta_v \cos\theta_l} L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l\f]
Next transformations of these expressions require understanding of numerical way to find hemisphere integral and also its performance optimization techniques.
And that the topic of the next chapter.
# Monte-Carlo numeric integration
**Monte-Carlo** is one of numeric methods to **find integral**.
It is based on idea of mathematical expectation calculation.
In one dimensional case if \f$f(x)\f$ is a function with parameter distributed according to probability density \f$p(x)\f$ the mathematical expectation of it can be found using following expression:
\f[E = \int\limits_{-\infty}^\infty f(x) p(x)\, \mathrm{d}x\f]
Also this expectation can be approximated in statistical term using certain sequence of random variable \f$x\f$:
\f[E \approx \frac{1}{N} \sum_{i=1}^{N} f(x_i)\f]
It can be used in general definite integrals calculations.
Just valid \f$p(x)\f$ defined on \f$[a, b]\f$ range and sequence \f$x_i\f$ generated according to it are needed for that:
\f[\int\limits_a^b f(x)\, \mathrm{d}x = \int\limits_a^b \frac{f(x)}{p(x)}p(x)\, \mathrm{d}x = \int\limits_{-\infty}^{\infty} \frac{f(x)}{p(x)}p(x)\, \mathrm{d}x \approx \frac{1}{N} \sum_{i=1}^{N} \frac{f(x_i)}{p(x_i)}\f]
Where \f$f(x)\f$ is considered to be equal to zero outside of \f$[a, b]\f$ range.
This is also true for functions on sphere or hemisphere:
\f[\int\limits_{H|S} f(l)\, \mathrm{d}l \approx \frac{1}{N}\sum_{i=1}^{N} \frac{f(l_i)}{p(l_i)}\f]
The main questions are choosing \f$p(l)\f$ and generating samples \f$l_i\f$.
The one of the simple ways is uniform distribution along sphere or hemisphere.
Lets realize that on sphere for example.
There are \f$4\pi\f$ possible directions in terms of sphere's areas and steradians (direction can be presented as dot on a unit sphere):
\f[\int\limits_S 1\, \mathrm{d}l = 4\pi\f]
Where \f$S\f$ is the unit sphere.
In order to be uniform \f$p(l)\f$ must be constant and satisfy normalization criteria:
\f[\int\limits_S p(l)\, \mathrm{d}l = 1\f]
So that \f$p(l) = \frac{1}{4\pi}\f$.
Usually direction \f$l\f$ is parametrized by spherical coordinates \f$\phi \in [0, 2\pi]\f$ and \f$\theta \in [0, \pi]\f$ boiling down to the 2D samples generation.
But in these terms joint \f$p(\theta, \phi)\f$ will be looked slightly different due to variables transition.
\f$l\f$ is defined in regular Cartesian coordinates \f$l=(x, y, z)\f$ with \f$\|l\| = 1\f$.
The spherical coordinates transform looks like:
\f[x = r\sin\theta\cos\phi,\, y = r\sin\theta\sin\phi,\, z = r\cos\theta\f]
Where \f$r = 1\f$.
In order to express probability density using new variables it is needed to multiply this density by Jacobian of transform:
\f[p(\theta,\phi) = p(l)|J_T|\f]
Where:
\f[|J_T| = \begin{vmatrix} \frac{\partial x}{\partial r} & \frac{\partial x}{\partial \theta} & \frac{\partial x}{\partial \phi} \\ \frac{\partial y}{\partial r} & \frac{\partial y}{\partial \theta} & \frac{\partial y}{\partial \phi} \\ \frac{\partial z}{\partial r} & \frac{\partial z}{\partial \theta} & \frac{\partial z}{\partial \phi} \end{vmatrix} = r^2\sin\theta\f]
So that joint probability density in new variables looks like:
\f[p(\theta, \phi) = \frac{\sin\theta}{4\pi}\f]
This variable transfer rule of **Probability Density Function** (**PDF**) will be useful in following chapters, when integral calculation optimization techniques will be being told.
Having \f$p(\theta, \phi)\f$ the partial single dimensional probability densities are able to be found:
\f[p(\phi) = \int\limits_0^\pi p(\theta, \phi)\, \mathrm{d}\theta = \frac{1}{4\pi} \int\limits_0^\pi \sin\theta\, \mathrm{d}\theta = \frac{1}{2\pi}\f]
\f[p(\theta) = \int\limits_0^{2\pi} p(\theta, \phi)\, \mathrm{d}\phi = \frac{\sin\theta}{4\pi}\int\limits_0^{2\pi}1\, \mathrm{d}\phi = \frac{\sin\theta}{2}\f]
The final step is sequence generation itself.
In order to be able to generate values with arbitrary distributions it is helpful to start from uniform numbers in range of \f$[0, 1]\f$.
And that can be done via any known true- and pseudo- random generators.
Even simple \f$\frac{1}{i}\f$ sequence is appropriate for beginning but it can be not so efficient in terms of computations convergence.
There are specially designed series for the last reason and it will be tackled in chapter about optimizations.
The \f$\phi\f$ variable is noticed to be uniformly distributed so that it can be directly generated without any additional manipulations.
Just range \f$[0, 1]\f$ is needed to be mapped to range \f$[0, 2\pi]\f$.
For any other variables including \f$\theta\f$ the inverse transform sampling approach can be applied.
First of all **cumulative distribution function** (**CDF**) is needed to be found.
It is probability of random value to be less than argument of this functions by definition.
For continues distributions it can be expressed in following form:
\f[F(x) = \int\limits_{-\infty}^x p(x')\, \mathrm{d}x'\f]
Lets find CDF for \f$\theta\f$:
\f[F(\theta) = \int\limits_{-\infty}^\theta p(\theta')\, \mathrm{d}\theta' = \int\limits_0^\theta \frac{\sin\theta'}{2}\, \mathrm{d}\theta' = \frac{1-\cos\theta}{2}\f]
The CDF maps \f$\theta\f$ values from range of \f$[0, \pi]\f$ to probability in range of \f$[0, 1]\f$.
The next step is to find inverse cumulative function which can be not so trivial sometimes but pretty obvious in current case:
\f[F^{-1}(u) = \arccos(1-2u)\f]
If substitute uniform distributed in range \f$[0, 1]\f$ values \f$u\f$ as argument of this function the values with origin probability density will appear.
In other words:
\f[\theta = \arccos(1 - 2u),\, u \in [0, 1],\, p(u) = 1 \Rightarrow p(\theta) = \frac{\sin\theta}{2}\f]
That is the key of this random values generation technique.
All steps described above can be also done for hemisphere:
\f[p(l) = \frac{1}{2\pi}\f]
\f[p(\theta, \phi) = \frac{\sin\theta}{2\pi}\f]
\f[p(\phi) = \int\limits_0^\frac{\pi}{2} p(\theta, \phi)\, \mathrm{d}\theta = \frac{1}{2\pi} \int\limits_0^\frac{\pi}{2} \sin\theta\, \mathrm{d}\theta = \frac{1}{2\pi}\f]
\f[p(\theta) = \int\limits_0^{2\pi} p(\theta, \phi)\, \mathrm{d}\phi = \frac{\sin\theta}{2\pi}\int\limits_0^{2\pi}1\, \mathrm{d}\phi = \sin\theta\f]
\f[\theta = \arccos(1-u)\f]
Mote-Carlo integration cannot guarantee exact estimation of convergence speed with using random generated samples.
There is only probability estimation of it.
But this algorithm is pretty universal and relatively simple to be applied to almost any function using at least uniform distributed points.
Moreover special \f$p(l)\f$ can be chosen and special pseudo-random sequences can be designed in order to speed up convergence for some functions (following chapter talk about that in details).
That is why this method is widely used in computer graphics and demonstrates good results.
Also another one advantage is worth to be mentioned - possibility to iteratively accumulate computations and present intermediate results during rendering which is used in some ray tracing applications.
# Split sum
Lets go back to the image based lighting and the figure of specular component.
As was defined before that is hemisphere integral with following expression:
\f[L_{indirect}^s = \frac{1}{4}\int\limits_H \frac{DFG}{\cos\theta_v \cos\theta_l} L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l\f]
The Monte-Carlo integration algorithm can be directly applied:
\f[L_{indirect}^s = \int\limits_H f_s(v, l)L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l \approx \frac{1}{N}\sum_{i=1}^N \frac{f_s(v, l_i) L_i^{indirect}(l_i) \cos\theta_{l_i}}{p(v, l_i)}\f]
\f$p(v, l_i)\f$ depends on \f$v\f$ and implicitly on \f$r\f$ in order to be completely general.
Optimization strategies use different samples distributions for different view direction orientations and roughness values.
Anyway even with all optimization techniques this algorithm continues to require too much calculations.
Good visual results require noticeable number of samples and using this approach for every point in real time rendering becomes unrealistic.
The way to avoid these enormous calculations is doing them beforehand somehow.
The first trick on the way to this is split the sum separating environment light component:
\f[L_{indirect}^s \approx \frac{1}{N} \sum_{i=1}^N \frac{f_s(v, l_i) L_i^{indirect}(l_i) \cos\theta_{l_i}}{p(v, l_i)} \approx \left( \frac{1}{N} \sum_{i=1}^N L_i^{indirect}(l_i) \right) \left( \frac{1}{N} \sum_{i=1}^N \frac{f_s(v, l_i) \cos\theta_{l_i}}{p(v, l_i)} \right)\f]
Where the second brackets represent approximation of integral so that the expression can be rewritten as:
\f[L_{indirect}^s \approx \frac{1}{N} \sum_{i=1}^N \frac{f_s(v, l_i) L_i^{indirect}(l_i) \cos\theta_{l_i}}{p(v, l_i)} \approx \left( \frac{1}{N} \sum_{i=1}^N L_i^{indirect}(l_i) \right) \int\limits_H f_s(v, l) \cos\theta_l\, \mathrm{d}l\f]
This integral is exact \f$L_{indirect}^s\f$ in condition when \f$L_i^{indirect}(l) = 1\f$ what just means white uniform environment.
The sum before it is kind of averaged environment illumination.
The main accomplishment after all this manipulations is possibility to calculate light and BRDF components separately.
The sum with \f$L_i^{indirect}(l_i)\f$ can be computed beforehand for every normal direction and stored to image called specular map but with some valuable details.
The problem is that \f$l_i\f$ samples must be generated according to \f$p(v, l_i)\f$ distribution depended on \f$v\f$ and \f$r\f$ as was mentioned earlier.
Variation of normal is not enough in that case and these variables are needed to be considered too.
The ways to resolve it are topic of one of the following chapters and now understanding the fact that at least this part can be precomputed before rendering is enough for now.
And it is important not to miss out that there is no more BRDF influence in this sum and only \f$p(v, l)\f$ can affect in this case.
That is why it is so important to strict to PDF during samples generation and that is why \f$p(v, l)\f$ must be correlated with BRDF somehow in this approximation approach with splitting.
For example completely mirroring materials with \f$r = 0\f$ will not be looked as expected if just uniform distribution is used
because such surfaces have only one possible direction from which light can be reflected along view direction in compare with \f$N\f$ absolutely scattered in case of uniform or many other distributions.
The rest part also can be saved to image. Lets unroll its expression:
\f[\int\limits_H f_s(v, l) \cos\theta_l\, \mathrm{d}l = \int\limits_H \frac{DGF}{4\cos\theta_v \cos\theta_l} \cos\theta_l\, \mathrm{d}l\f]
This integral is not actually a scalar.
That is RGB value due to only \f$F\f$ factor and even more only to \f$F_0\f$.
In order to simplify future computations \f$F_0\f$ is needed to be moved out of integral.
Substitution of Schlick's approximation helps to achieve it:
\f[F = F_0+(1-F_0)(1-\cos\theta_{vh})^5 = F_0(1-(1-\cos\theta_{vh})^5) + (1-\cos\theta_{vh})^5\f]
\f[\int\limits_H \frac{DGF}{\cos\theta_v \cos\theta_l} \cos\theta_l\, \mathrm{d}l = F_0 \int\limits_H \frac{DG}{4\cos\theta_v \cos\theta_l} (1-(1-\cos\theta_{vh})^5) \cos\theta_l\, \mathrm{d}l + \int\limits_H \frac{DG}{4\cos\theta_v \cos\theta_l} (1-\cos\theta_{vh})^5 \cos\theta_l\, \mathrm{d}l\f]
This form may not look easier, but it has several advantages.
The first one is independence from globally defined \f$L_i^{indirect}(l)\f$, so that normal orientation does not matter and can be set in any handful way for calculations (Z axis for example).
The second one results from isotropic illumination system allowing \f$\phi\f$ component of view vector to be set arbitrarily (0 for example) and \f$\cos\theta_v\f$ will be enough to define view direction.
And the third one is scalar nature of integrals so that only two precomputed numbers are needed to find BRDF part of \f$L_{indirect}^s\f$.
Considering dependency of these integrals from \f$\cos\theta_v\f$ and \f$r\f$ both of it can be precomputed and stored to 2D look-up image variating these two parameters in range \f$[0, 1]\f$ with two channels consisting of scale and bias for \f$F_0\f$.
Current result for \f$L_{indirect}^s\f$ is computing it using 2D image for BRDF part and omnidirectional image for environment illumination.
There were a lot of words about Monte-Carlo optimizations techniques and about PDF choice which is important not only in terms of numeric integration but in terms of visual results correctness.
It's time to talk about that.
# Importance sampling
Current goal is to speed up Monte-Carlo integration of Cook-Torrance like integrals with following expression:
\f[\int\limits_H \frac{DG}{4\cos\theta_v \cos\theta_l} g(v, l) \cos\theta_l\, \mathrm{d}l\f]
Where \f$g(v, l)\f$ is just arbitrary function representing Fresnel's factor itself or its components.
In order to increase convergence the samples with larger contribution (or in other words with larger function's values) have to appear more frequently than others proportionally to its contribution.
So that less significant summand with less influence to result will be considered rarely and in opposite way parts brining noticeable changes to the sum will be taken often.
That is the main idea of **importance sampling technique**.
\f$p(l)\f$ has to represent significance of sample in terms of integrated function via probability somehow.
And it will be like that if PDF is already part of original function because in that case probability density directly affects to contribution forming.
Separating this distribution component is one possible and effective way to realize importance sampling strategy.
In integral presented above PDF part already exists and that is \f$D\f$ component.
But it is distribution of micro faces normals or ideally reflection direction or \f$h\f$ in other word and not light directions distribution which is needed in fact.
Anyway that is good starting point and lets generate \f$h\f$ vectors first.
\f$D\f$ has the following expression:
\f[D=\frac{\alpha^2}{\pi(\cos^2\theta_h(\alpha^2-1) + 1)^2}\f]
Frankly speaking \f$D(h)\f$ is called normal distribution but cannot be directly used as hemisphere distribution.
Originally it is statistical factor used to define total area of micro faces \f$\mathrm{d}A_h\f$
whose normals lie withing given infinitesimal solid angle \f$\mathrm{d}h\f$ centered on \f$h\f$ direction using the original small enough area of macro surface \f$\mathrm{d}A\f$:
\f[dA_h = D(h)\,\mathrm{d}h\, \mathrm{d}A\f]
First of all this factor must be positive:
\f[D(h) \geq 0\f]
But the total area of micro faces landscape is at least equal to origin surface but even bigger in general:
\f[1 \leq \int\limits_H D(h)\, \mathrm{d}h\f]
This trait does not allow to use \f$D\f$ as hemisphere distribution.
But it can be fixed with following feature:
\f[\forall v\, \int\limits_H D(h)(v \cdot h)\, \mathrm{d}h = (v \cdot n)\f]
Which means that total area of micro faces projected to any direction must be the same as projected area of origin macro surface.
It is pretty tricky trait in \f$D\f$ definition but it leads to interesting results in condition when \f$v = n\f$:
\f[\int\limits_H D(h)\cos\theta_h\, \mathrm{d}h = 1\f]
So that \f$\cos\theta_h\f$ coefficient normalizes normal distribution in terms of hemisphere and allows to use it as distribution.
Finally PDF of half vectors can be wrote:
\f[p(\theta_h, \phi_h) = D\cos\theta_h\sin\theta_h = \frac{\alpha^2 \cos\theta_h\sin\theta_h}{\pi(\cos^2\theta_h(\alpha^2-1) + 1)^2}\f]
\f$\sin\theta_h\f$ results from spherical coordinate system transfer which was described in Monte-Carlo integration chapter.
Lets strict to samples generation procedure and find partial probability densities:
\f[p(\phi_h) = \int\limits_0^\frac{\pi}{2} p(\theta_h, \phi_h)\, \mathrm{d}\theta_h = \int\limits_0^\frac{\pi}{2} \frac{\alpha^2 \cos\theta_h\sin\theta_h}{\pi(\cos^2\theta_h(\alpha^2-1) + 1)^2}\, \mathrm{d}\theta = \frac{1}{2\pi}\f]
\f[p(\theta_h) = \int\limits_0^{2\pi} p(\theta_h, \phi_h)\, \mathrm{d}\phi_h = \int\limits_0^{2\pi} \frac{\alpha^2 \cos\theta_h\sin\theta_h}{\pi(\cos^2\theta_h(\alpha^2-1) + 1)^2}\, \mathrm{d}\phi = \frac{2 \alpha^2 \cos\theta_h\sin\theta_h}{(\cos^2\theta_h(\alpha^2-1) + 1)^2}\f]
\f$p(\phi_h)\f$ is unnecessary to be calculated analytically.
The fact of independency from \f$\phi\f$ is enough to figure out that this coordinate is uniformly distributed.
Anyway the \f$F(\theta_h)\f$ is next step:
\f[F(\theta_h) = \int\limits_0^{\theta_h} \frac{2 \alpha^2 \cos\theta'_h\sin\theta'_h}{(\cos^2\theta'_h(\alpha^2-1) + 1)^2}\, \mathrm{d}\theta'_h = \int\limits_{\theta_h}^0 \frac{2 \alpha^2}{(\cos^2\theta'_h(\alpha^2-1) + 1)^2}\, \mathrm{d}(\cos^2\theta'_h) = \frac{\alpha^2}{\alpha^2-1}\int\limits_0^{\theta_h} \mathrm{d}\frac{1}{\cos^2\theta'_h(\alpha^2-1)+1} =\f]
\f[ = \frac{\alpha^2}{\alpha^2-1} \left( \frac{1}{\cos^2\theta_h(\alpha^2-1) + 1} - \frac{1}{\alpha^2} \right) = \frac{\alpha^2}{\cos^2\theta_h(\alpha^2-1)^2+(\alpha^2-1)} - \frac{1}{\alpha^2-1}\f]
In order to apply inverse transform sampling the \f$F^{-1}(u)\f$ is needed to be found:
\f[F^{-1}(u) = \theta_h = \arccos\sqrt{\frac{1-u}{u(\alpha^2-1)+1}}\f]
So that there is no more obstacles to generate \f$h\f$.
But the main goal was \f$l\f$ direction.
In order to get it the view vector \f$v\f$ has to be reflected related to already found \f$h\f$:
\f[l = 2(v \cdot h)h - v\f]
That is practical side of light direction generation.
But the theoretical one is needed to be resolved to calculate sum.
It is time to find \f$p(l)\f$ using known \f$p(h)\f$.
First of all the fact that \f$l\f$ is just transformed \f$h\f$ is needed to be understood.
In that way the light direction's PDF has following expression:
\f[p(l) = p(h)|J_T|\f]
Where \f$|J_T|\f$ is Jacobian of reflection transformation.
Lets find it.
Right now \f$n\f$ is axis from which \f$\theta\f$ spherical coordinate is encountered.
The first step is setting \f$v\f$ as starting point of \f$\theta\f$ instead of \f$n\f$.
This is linear transform so that \f$|J_T| = 1\f$.
Next step is transfer to spherical coordinate with \f$|J_T| = \sin\theta_{vh}\f$.
Due to previous step \f$\theta_{vh}\f$ is used instead of \f$\theta_h\f$.
In this coordinate system reflecting of \f$v\f$ relative to \f$h\f$ is just doubling \f$\theta_{vh}\f$ and Jacobian of it is equal to \f$\frac{1}{2}\f$.
In series of transform the Jacobians are multiplied so that currently \f$|J_T| = \frac{1}{2}\sin\theta_{vh}\f$.
And the final step is inverse transform to Cartesian coordinate system with \f$|J_T| = (\sin\theta_{vl})^{-1} = (\sin2\theta_{vh})^{-1}\f$.
Combining this all together the following expression is obtained for reflection transform Jacobian:
\f[|J_T| = \frac{\sin\theta_{vh}}{2\sin2\theta_{vh}} = \frac{\sin\theta_{vh}}{4\sin\theta_{vh}\cos\theta_{vh}} = \frac{1}{4\cos\theta_{vh}}\f]
And finally \f$p(l)\f$ looks like:
\f[p(l) = p(h)|J_T| = \frac{D\cos\theta_h}{4\cos\theta_{vh}}\f]
Lets go back to the Monte-Carlo sum and insert found result to it:
\f[\int\limits_H \frac{DG}{4\cos\theta_v \cos\theta_l} g(v, l) \cos\theta_l\, \mathrm{d}l \approx \frac{1}{N} \sum_{i=1}^N \frac{DG\, g(v, l_i) \cos\theta_{l_i}}{4\cos\theta_v \cos\theta_{l_i}\, p(l_i)} = \frac{1}{N} \sum_{i=1}^N \frac{G\, g(v, l_i) \cos\theta_{l_i} \cos\theta_{vh_i}}{\cos\theta_v \cos\theta_{l_i} \cos\theta_{h_i}}\f]
Here \f$G\f$ component is recommended to be calculated with original \f$k=\frac{\alpha}{2} = \frac{r^2}{2}\f$ in order to get more plausible result.
Of course, all \f$\cos\f$ must be clamped to range \f$[0, 1]\f$ because integral is calculated on a hemisphere and all expressions are defined on it.
\f$\cos\theta_v \cos\theta_{l_i}\f$ in denominator can be reduced with exactly the same part in geometric attenuation factor in order to avoid additional zero division cases.
Summarizing importance sampling strategy described above the convergence of Monte-Carlo integration can be improved using special PDF correlated with integrated function.
In case of BRDF with normal distribution functions \f$D\f$ the PDF producing procedure is defined.
Practically half vector \f$h\f$ is generated first and \f$l\f$ is obtained from it by view vector \f$v\f$ reflecting.
Due to this transformation final form of probability density used in sum is quite different but also has defined algorithm of calculation.
For isotropic Cook-Torrance BRDF the \f$\cos\theta_v\f$ and roughness \f$r\f$ are enough to start generation so that all integrals of that kind can be precalculated in 2D look-up tables variating these two parameters.
The same samples generation procedure must be used in specular map baking described in next chapter.
# Specular map
The situation with BRDF part of \f$L_{indirect}^s\f$ is clear now and \f$L_i^{indirect}(l)\f$ sum is left to be discussed.
That was called **specular map** and has following form:
\f[\frac{1}{N}\sum_{i=1}^N L_i^{indirect}(l_i)\f]
As was mentioned this sum must be calculated for every normal direction using the same samples generation principles as in numeric integration computation.
This principles require two scalar parameters \f$\cos\theta_v\f$ and \f$r\f$ but now \f$\phi\f$ really matters.
So that in fact the specular map has to be saved in 3D table consisting omnidirectional textures.
That is a big expense of computational and memory resources.
A couple of tricks helps to reduce dimensions.
First of all the \f$\cos\theta_v\f$ and \f$\phi\f$ can be just excluded.
In that way \f$v\f$ is considered to be equal to \f$n\f$.
Of course this approach produces an error and affects the final result.
It can be fixed more or less by \f$\cos\theta_{l_i}\f$ weighting:
\f[\frac{1}{N} \sum_{i=1}^N L_i^{indirect}(l_i) \cos\theta_{l_i}\f]
It is not a complete solution but practice shows that it is enough to get plausible illumination with sacrificing of lengthy reflections at grazing angles which exist in fact if everything is honestly computed.
The problem is that for \f$v \neq n\f$ considering this sum to be defined related to \f$n\f$ became incorrect.
For example, for complete mirroring materials with \f$r = 0\f$ this sum must boil down to \f$L_i^{indirect}(v_r)\f$
but not to \f$L_i^{indirect}(n)\f$ where \f$v_r\f$ is just reflected \f$v\f$ or in other words \f$v_r = 2(v \cdot n)n - v\f$.
That it just mirroring reflection principle.
Assumption of \f$n = v\f$ also means that \f$n = v = v_r\f$.
In that way radiance map better to be considered as averaging of illumination coming from \f$v_r\f$.
So that it has become to be defined related to reflection direction which has to be calculated before map's fetching.
Anyway, there are just two dimensions in radiance look-up table remain.
The rest one with \f$r\f$ parameter cannot be reduced.
There is no other ways except just roughness variation but in order to simplify that computations can be done for several values and the rest ones lying between can be obtained from linear interpolation.
This is another source of visual artifacts but it also works good in practice and that is pretty common approach.
But it still requires noticeably amount of samples and that is for every pixel related to each \f$r\f$ value.
It can be appropriate for precomputations but still limits using dynamic environments in real time rendering or just even static environments but on weak devices such as mobile ones.
And there are several possible ways to improve radiance map baking performance.
The first one is using textures with smaller resolutions for larger roughnesses.
The point is that smaller \f$r\f$ values produce map saving more details from origin environment in opposite to larger ones representing lower frequency components and working as low pass filters in fact.
So less pixels in combination with linear interpolation is enough to store less detailed convolutions.
Moreover, this approach naturally works with textures levels of details in graphics API
so that every certain radiance map related to certain \f$r\f$ can be stored on its own mip level and be directly fetched with linear interpolation not only over one texture but over levels too.
As practice shows 6 levels are enough.
After reducing pixels count it is turn for samples number.
And again correlation with roughness can be noticed.
For example map for completely mirroring materials with \f$r = 0\f$ the same sample \f$l_i = v_r\f$ will be produced.
So that only one sample is enough in this case.
In opposite way directions for \f$r = 1\f$ will be scattered over almost whole hemisphere what requires as much samples as available.
The 'locality' of distribution is decreased during increasing roughness and it is possible to assume that samples number might to be proportional to this 'locality' keeping accuracy at the same level.
But how can 'locality' be interpreted in terms of probability distribution? One possible way is CDF meaning.
\f$F(\theta_h)\f$ has been already defined and by definition it shows the probability of random value \f$\theta_h\f$ to be less than argument of CDF.
In other words \f$F(\theta'_h) = u\f$ means that probability of \f$\theta_h\f$ to be in range of \f$[0, \theta'_h]\f$ is \f$u\f$.
The inverse task of range searching using given \f$u\f$ can be solved with help of \f$F^{-1}(u) = \theta'_h\f$.
If \f$u\f$ is close to 1 (exact 1 has no sense because in that case \f$\theta'_h = \max\theta_h = \frac{\pi}{2}\f$)
then \f$\theta'_h\f$ represents the range of the most probable or most frequently generated values and that can be interpreted as 'locality' of distribution.
After that if samples number of the worst case with \f$r = 1\f$ is set (\f$N(1) = \max N\f$) the other ones can be estimated using following formula:
\f[N(r) = N(1)\frac{\theta'_h(r)}{\frac{\pi}{2}} = N(1)\frac{2\theta'_h(r)}{\pi} = N(1)\frac{2F^{-1}(u)}{\pi} = N(1)\frac{2}{\pi}\arccos\sqrt{\frac{1-u}{u(\alpha^2-1)+1}}\f]
It is approximate expression representing only estimated general proportionality so that cases of \f$r = 0\f$ and \f$r = 1\f$ must be processed separately with \f$N(0) = 1\f$ and \f$N(1) = \max N\f$.
\f$u\f$ can be parameter of this optimization strategy controlling speed of samples reducing in order to balance performance and quality (\f$u = 1\f$ disables this optimization at all).
This pretty tricky technique allows reducing calculations for every pixels without sacrificing the quality.
In addition to optimizations mentioned before another one can be applied in order to help to reduce samples numbers as previous one.
Using less samples produces image noise due to discrete nature of Monte-Carlo approximation.
But it can be slightly smoothed using some prefiltration.
The idea is that for the directions with small PDF or in other words for rare directions the samples near of it is unlikely to be generated.
So that this direction represents the averaged illumination from relatively big area on hemisphere but approximate it by just a constant.
It wold be better to get from such direction already averaged over bigger area environment.
It can be achieved using mip levels of origin \f$L_i^{indirect}\f$ whose pixels of one level is exact 4 averaged pixels from previous one.
Also mip levels generation is build in most common graphic API so there are no problems with it.
But first of all the area covered by one sample is needed to be found.
And that can be done as:
\f[\Omega_s = \frac{1}{N\,p(l)} = \frac{4\cos\theta_{vh}}{ND\cos\theta_h}\f]
Circumstance of \f$v = v_r = n\f$ leads to \f$\cos\theta_{vh}\f$ and \f$\cos\theta_h\f$ reducing so expression becomes even simpler:
\f[\Omega_s =\frac{4}{ND}\f]
Of course all zero divisions must be avoided by clamping, for example.
After that the area covered by one pixel of environment map is calculated.
In case of a cube map it looks like:
\f[\Omega_p = \frac{4\pi}{6k^2}\f]
Where \f$k\f$ is size of one cube map side in pixels (sides are assumed to be quads).
Finally the mip level of origin environment map which is needed to be fetched for this certain sample is defined by following expression:
\f[lod = \frac{1}{2} \log_2\left(\frac{\Omega_s}{\Omega_p}\right)\f]
The mathematics connected with mip levels sizes lie behind it but this is out of scope of this paper.
In combination with previous optimization technique this approach allows \f$N(1)\f$ to be smaller keeping visual results good.
That is not all possible optimization tricks but at least these three significantly reduces compute efforts and brings radiance map calculation to weak devices or even to dynamic environments in real time but in reasonable limits.
In that way \f$L_{indirect}^s\f$ can be completely computed without any integral approximations.
Only 2D look-up table of BRDF part and mip mapped omnidirectional texture of irradiance map are needed.
The first one can be got even without any environment.
It was achieved using some rough approximations and assumptions but despite of that the visual result are still plausible and can be compared even with ray traced images.
In order to complete whole image based lighting the \f$L_{indirect}^d\f$ component is left to be discussed.
# Spherical harmonics
Lets go back to diffuse indirect illumination component represented by following formula:
\f[L_{indirect}^d = (1-m)\frac{c}{\pi}\int\limits_H (1-F)L_i^{indirect}(l)\cos\theta_l\, \mathrm{d}l\f]
Of course, Monte-Carlo algorithm can be applied directly and hemisphere integral can be precalculated for every normal direction
but dependence from \f$v\f$ in Fresnel's factor does not allow to do it efficiently (every \f$v\f$ direction is needed to be considered again).
In order to resolve it modified version of Schlick's approximation has been created:
\f[F \approx F_{ss}=F_0+(\max(1-r, F_0))(1-\cos\theta_v)^5\f]
It differs from origin one and loses accuracy a little bit but now there is no light direction inside
so that it can be considered as kind of screen space defined Fresnel's factor (\f$ss\f$ means exactly 'screen space') and can be removed from integral:
\f[L_{indirect}^d = (1-m)(1-F_{ss})\frac{c}{\pi} \int\limits_H L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l\f]
The resulted expression without \f$(1-m)\f$ and \f$(1-F_{ss})\f$ parts is pretty known entity called **irradiance**.
It can be precalculated using \f$\cos\theta_l\f$ as PDF for importance sampling (actually it is only option in this case excluding uniform distribution).
But even with that samples will be scattered almost over whole hemisphere.
As was discussed in previous chapter this case requires significant amount of samples in order to average illumination with appropriate quality.
Poor accuracy resulted from lack of summand can be noticed especially on high frequency environments having a lot of contrasting details.
It worth to be mentioned that irradiance is used not only in BRDF.
Omnidirectional diffuse illumination captured for certain point or even for several points uniformly or hierarchically distributed is base of some baking global illumination techniques.
There it is called a **light probe**. So that other way to compute and store irradiance maps was found resolving many mentioned problems.
The Fourier's decomposition analogue for spherical function allows to achieve this.
That would be easy to explain concept directly on example.
So lets start from \f$L_i^{indirect}(l)\f$.
It is spherical function because directions are just points on sphere.
The decomposition looks like:
\f[L_i^{indirect}(l) = \sum_{i = 0}^\infty \sum_{j=-i}^i L_i^j y_i^j(l)\f]
Where \f$y_i^j(l)\f$ are spherical functions forming orthonormalized basis called spherical harmonics and \f$L_i^j\f$ is decompositions coefficients.
Orthonormality means that dot product of two basis elements is equal to 1 if this is the same functions and is equal to zero otherwise.
Dot product on a sphere is defined as integral of functions multiplication. In other words:
\f[\int\limits_S y_i^j(l)\, y_{i'}^{j'}(l)\, \mathrm{d}l = \begin{cases} 1 & \quad i,j = i',j' \\ 0 & \quad \mathrm{otherwise}\end{cases}\f]
Function basis with such traits is known and is described by following formulas:
\f[y_i^{j > 0}(\theta, \phi) = \sqrt{2}K_i^j\cos(j\phi)P_i^j(\cos\theta)\f]
\f[y_i^{j<0}(\theta, \phi) = \sqrt{2}K_i^j\sin(j\phi)P_i^{|j|}(\cos\theta)\f]
\f[y_i^0(\theta, \phi) = K_i^0P_i^0(\cos\theta)\f]
\f[K_i^j = \sqrt{\frac{(2i+1)(i-|j|)!}{4\pi(i+|j|)!}}\f]
\f[P_0^0(x) = 1\f]
\f[P_1^0(x) = x\f]
\f[P_i^i(x) = (-1)^i(2i-1)!!(1-x^2)^\frac{i}{2}\f]
\f[P_i^j(x) = \frac{(2i-1)xP_{i-1}^j(x) - (i + j - 1)P_{i-2}^j}{i - j}\f]
Here \f$K_i^j\f$ are normalization factors and \f$P_i^j\f$ are **Legendre's polynomials**.
Decomposition coefficients \f$L_i^j\f$ are dot product of origin function (\f$L_i^{indirect}(l)\f$ in current case) and corresponding basis element. It can be written down as:
\f[L_i^j = \int\limits_S L_i^{indirect}(l)\,y_i^j(l)\, \mathrm{d}l\f]
Fact that all calculation happen over a sphere but not over hemisphere right now is important not to be missed.
That was example of spherical function decomposition but not a solution for original task which looks like:
\f[\int\limits_H L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l\f]
First of all, lets transform this integral to be defined not over hemisphere but sphere:
\f[\int\limits_H L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l = \int\limits_S L_i^{indirect}(l)\overline{\cos}\theta_l\, \mathrm{d}l\f]
Where \f$\overline{\cos}\f$ is cosine clamped to zero which can be expressed as:
\f[\overline{\cos}\theta_l = \max(\cos\theta_l, 0)\f]
Resulted expression can be considered as convolution in terms of spherical functions where \f$L_i^{indirect}(l)\f$ is target and \f$\overline{\cos}\theta_l\f$ is core.
This integral may seem independent but in fact hemisphere is oriented related to \f$n\f$ therefore \f$\overline{\cos}\theta_l\f$ depends on it too and became a kind of 'oriented' version of cosine.
That is pretty tricky and explanation about meaning of convolution on sphere is out of scope of this paper.
Fact that this is convolution analogue related to \f$n\f$ is enough for now.
The goal of looking at integral from this angle is using of convolution's trait allowing to compute decomposition using just only coefficients of function and core.
\f$\overline{\cos}\theta_l\f$ is independent from \f$\phi_l\f$ and in case of such radial symmetric cores the resulting coefficients boil down to following formula:
\f[(L_i^{indirect}(l) \ast \overline{\cos}\theta_l)_i^j = \frac{1}{K_i^0}L_i^j\, c_i^0 = \sqrt{\frac{4\pi}{2i+1}}L_i^j\, c_i^0\f]
Where \f$c_i^0\f$ are spherical harmonics factors corresponding to \f$\overline{\cos}\theta\f$.
Therefore the final decomposition looks like:
\f[\int\limits_{H(n)} L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l = \int\limits_S L_i^{indirect}(l)\overline{\cos}\theta_l\, \mathrm{d}l = \sum_{i=0}^\infty \sum_{j = -i}^i \sqrt{\frac{4\pi}{2i+1}}L_i^j\, c_i^0\, y_i^j(n)\f]
\f$c_i^0\f$ is left to be found.
Due to independence from \f$\phi\f$ all \f$c_i^{j \neq 0} = 0\f$.
The rest ones are calculated by regular dot product with basis functions:
\f[c_i^0 = c_i = \int\limits_S y_i^0(l)\, \overline{\cos}\theta_l\, \mathrm{d}l = \int\limits_0^{2\pi} \mathrm{d}\phi \int\limits_0^\pi y_i^0(\theta, \phi)\, \overline{\cos}\theta \sin\theta\, \mathrm{d}\theta = \int\limits_0^{2\pi} \mathrm{d}\phi \int\limits_0^\frac{\pi}{2} y_i^0(\theta, \phi)\, \cos\theta\sin\theta\, \mathrm{d}\theta = \f]
\f[= 2\pi\int\limits_0^\frac{\pi}{2} y_i^0(\theta, \phi)\, \cos\theta\sin\theta\, \mathrm{d}\theta = 2\pi K_i^0\int\limits_0^\frac{\pi}{2} P_i^0(\cos\theta)\, \cos\theta\sin\theta\, \mathrm{d}\theta\f]
\f$\sin\theta\f$ appears due to transfer from integral over sphere to double integral where \f$\mathrm{d}l = \sin\theta\, \mathrm{d}\theta\, \mathrm{d}\phi\f$.
There is an analytical solution for this expressions:
\f[c_1 = \sqrt{\frac{\pi}{3}}\f]
\f[c_{odd} = 0 \quad c_{even} = 2\pi\sqrt{\frac{2i+1}{4\pi}}\frac{(-1)^{\frac{i}{2}-1}}{(i+2)(i-1)}\frac{i!}{2^i\left(\frac{i!}{2}\right)^2}\f]
Starting from about the third \f$c_i\f$ the coefficients become less and less valuable so that only couple of them is enough in order to approximate \f$\overline{\cos}\theta\f$ with appropriate accuracy.
The same principle is true for convolution too because its coefficients are multiplied by \f$c_i\f$.
So there is no need to use more than even three bands (\f$i = 0, 1, 2\f$) of basis functions.
Lets write down them all in Cartesian coordinate system:
\f[y_0^0 = \frac{1}{2}\sqrt{\frac{1}{\pi}} = Y_0^0\f]
\f[y_1^{-1} = -\frac{1}{2}\sqrt{\frac{3}{\pi}}y = Y_1^{-1}y\f]
\f[y_1^0 = \frac{1}{2}\sqrt{\frac{3}{\pi}}z = Y_1^0z\f]
\f[y_1^1 = -\frac{1}{2}\sqrt{\frac{3}{\pi}}x = Y_1^1x\f]
\f[y_2^{-2} = \frac{1}{2}\sqrt{\frac{15}{\pi}}xy = Y_2^{-2}xy\f]
\f[y_2^{-1} = -\frac{1}{2}\sqrt{\frac{15}{\pi}}yz = Y_2^{-1}yz\f]
\f[y_2^0 = \frac{1}{4}\sqrt{\frac{5}{\pi}}(3z^2-1) = Y_2^0(3z^2-1)\f]
\f[y_2^1 = -\frac{1}{2}\sqrt{\frac{15}{\pi}}xz = Y_2^1xz\f]
\f[y_2^2 = \frac{1}{4}\sqrt{\frac{15}{\pi}}(x^2-y^2) = Y_2^2(x^2-y^2)\f]
All \f$Y_i^j\f$ are just constants so that it can be moved from integral during calculations and can be taken from precomputed table.
Other constants related to \f$c_i\f$ can be united and also be calculated beforehand:
\f[\hat{c}_i = \frac{1}{K_i^0}\, c_i = \sqrt{\frac{4\pi}{2i+1}}\, c_i\f]
Finally expression of irradiance map approximation can be defined:
\f[\int\limits_{H(n)} L_i^{indirect}(l) \cos\theta_l\, \mathrm{d}l \approx \sum_{i=0}^2 \sum_{j=-i}^i L_i^j\, \hat{c}_i\, y_i^j(n)\f]
Where \f$\hat{c}_i\f$ is precalculated constants \f$y_i^j(n)\f$ are pretty easy functions and only \f$L_i^j\f$ are needed to be precomputed.
Of course \f$L_i^j\f$ are integrals over even whole sphere but now there is only nine of it instead of one for every pixel of omnidirectional image.
Moreover, texture is not needed at all in that case and only 9 colors representing \f$L_i^j\f$ have to be saved.
The Monte-Carlo algorithm can be applied with just uniform samples distribution without importance sampling at all.
\f$Y_i^j\f$ are used twice: in \f$L_i^j\f$ calculations and in sum after that.
So there is sense to store only squares of it.
All tables with constants presented below:
| |
|-|
| \f$(Y_0^0)^2 \approx (0.282095)^2\f$ |
| \f$(Y_1^{-1})^2 = (Y_1^0)^2 = (Y_1^1)^2 \approx (0.488603)^2\f$ |
| \f$(Y_2^{-2})^2 = (Y_2^{-1})^2 = (Y_2^1)^2 \approx (1.092548)^2\f$ |
| \f$(Y_2^0)^2 \approx (0.315392)^2\f$ |
| \f$(Y_2^2)^2 \approx (0.546274)^2\f$ |
| | |
|-|-|
| \f$\hat{c}_0\f$ | \f$3.141593\f$ |
| \f$\hat{c}_1\f$ | \f$2.094395\f$ |
| \f$\hat{c}_2\f$ | \f$0.785398\f$ |
Summarizing all mathematics above spherical harmonics decomposition boils down irradiance map to only 9 values which is needed to be precalculated as integrals.
As practice shows this is very good approximation of diffuse indirect illumination component.
# Transparent materials
TODO
# Low discrepancy sequence
TODO

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/occtJniActivity/libs&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/occtJniActivity/jni&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="~/develop/android-ndk-r10/ndk-build"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="V=1 jniall"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/occtJniActivity/jni}"/>
</launchConfiguration>

1
samples/java/jniviewer/.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.gradle eol=lf

View File

@@ -1,4 +1,10 @@
/assets
/bin
/gen
/libs
/.gradle
/.idea
/build
/gradle
gradlew
gradlew.bat
/app/.cxx
/app/build
gradle.properties
local.properties

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>occtJniActivity</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/C++ Builder.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -1,4 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -11,36 +11,22 @@ This sample demonstrates indirect method of wrapping C++ to Java using manually
Alternative method is available, wrapping individual OCCT classes to Java equivalents so that their full API is available to Java user
and the code can be programmed on Java level similarly to C++ one.
See description of OCCT Java Wrapper in Advanced Samples and Tools on OCCT web site at
http://www.opencascade.org/support/products/advsamples
https://www.opencascade.com/content/advanced-samples-and-tools
Run Eclipse from ADT (Android Developer Tools) for building the sample. To import sample project perform
~~~~
File -> Import... -> Android -> Existing Android code into Workspace
~~~~
and specify this directory. The project re-build will be started immediately right after importation if "Build automatically" option is turned on (default in Eclipse).
Proxy library compilation and packaging is performed by NDK build script, called by "C++ Builder" configured within Eclipse project.
The path to "ndk-build" tool from Android NDK (Native Development Kit) should be specified in Eclipse project properties:
~~~~
Project -> Properties -> Builders -> C++ Builder -> Edit -> Location
~~~~
Install Android Studio 4.0+ and install building tools (check Tools -> SDK Manager):
- Android SDK (API level 21 or higher).
- Android SDK build tools.
- Android NDK r16 or higher (coming with CMake toolchain).
Using NDK r18 or newer will require changing ANDROID_STL in project settings.
- CMake 3.10+.
Now paths to OCCT C++ libraries and additional components should be specified in "jni/Android.mk" file:
~~~~
OCCT_ROOT := $(LOCAL_PATH)/../../../..
Specify this folder location in Android Studio for opening project.
You might need re-entering Android SDK explicitly in File -> Project Structure -> SDK Location settings (SDK, NDK, JDK locations).
FREETYPE_INC := $(OCCT_ROOT)/../freetype/include/freetype2
FREETYPE_LIBS := $(OCCT_ROOT)/../freetype/libs
FREEIMAGE_INC := $(OCCT_ROOT)/../FreeImage/include
FREEIMAGE_LIBS := $(OCCT_ROOT)/../FreeImage/libs
OCCT_INC := $(OCCT_ROOT)/inc
OCCT_LIBS := $(OCCT_ROOT)/and/libs
~~~~
The list of extra components (Freetype, FreeImage) depends on OCCT configuration.
Variable $(TARGET_ARCH_ABI) is used within this script to refer to active architecture.
E.g. for 32-bit ARM build (see variable *APP_ABI* in "jni/Application.mk")
the folder *OCCT_LIBS* should contain sub-folder "armeabi-v7a" with OCCT libraries.
This sample expects OCCT to be already build - please refer to appropriate CMake building instructions in OCCT documentation.
The following variables should be added into file gradle.properties (see gradle.properties.template as template):
- `OCCT_ROOT` - path to OCCT installation folder.
- `FREETYPE_ROOT` - path to FreeType installation folder.
FreeImage is optional and does not required for this sample, however you should include all extra libraries used for OCCT building
and load the explicitly from Java code within OcctJniActivity::loadNatives() method, including toolkits from OCCT itself in proper order:
@@ -49,10 +35,8 @@ and load the explicitly from Java code within OcctJniActivity::loadNatives() met
|| !loadLibVerbose ("TKMath", aLoaded, aFailed)
|| !loadLibVerbose ("TKG2d", aLoaded, aFailed)
~~~~
Note that C++ STL library is not part of Android system.
Thus application must package this library as well as extra component.
"gnustl_shared" STL implementation is expected within this sample.
Note that C++ STL library is not part of Android system, and application must package this library as well as extra component ("gnustl_shared" by default - see also `ANDROID_STL`).
After successful build, the application can be packaged to Android:
- Deploy and run application on connected device or emulator directly from Eclipse using adb interface by menu items "Run" and "Debug". This would sign package with debug certificate.
- Prepare signed end-user package using wizard File -> Export -> Android -> Export Android Application.
After successful build via Build -> Rebuild Project, the application can be packaged to Android:
- Deploy and run application on connected device or emulator directly from Android Studio using adb interface by menu items "Run" and "Debug". This would sign package with debug certificate.
- Prepare signed end-user package using wizard Build -> Generate signed APK.

View File

@@ -0,0 +1,48 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.opencascade.jnisample"
minSdkVersion 21
targetSdkVersion 26
ndk {
abiFilters "arm64-v8a"
}
externalNativeBuild {
cmake {
arguments "-DOCCT_ROOT=" + OCCT_ROOT,
"-DFREETYPE_ROOT=" + FREETYPE_ROOT,
"-DANDROID_STL=gnustl_shared"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
assets.srcDirs = [OCCT_ROOT + "/src"]
}
}
externalNativeBuild {
cmake {
path "src/main/jni/CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(dir: 'java/com/opencascade/jnisample', include: ['*.jar'])
}

View File

@@ -31,6 +31,5 @@
</activity>
</application>
<uses-feature android:glEsVersion="0x00020000"/>
<uses-sdk android:minSdkVersion="15"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

View File

@@ -110,11 +110,8 @@ public class OcctJniActivity extends Activity implements OnClickListener
// copy OCCT resources
String aResFolder = getFilesDir().getAbsolutePath();
copyAssetFolder (getAssets(), "Shaders", aResFolder + "/Shaders");
copyAssetFolder (getAssets(), "SHMessage", aResFolder + "/SHMessage");
copyAssetFolder (getAssets(), "XSMessage", aResFolder + "/XSMessage");
copyAssetFolder (getAssets(), "TObj", aResFolder + "/TObj");
copyAssetFolder (getAssets(), "UnitsAPI", aResFolder + "/UnitsAPI");
copyAssetFolder (getAssets(), "src/SHMessage", aResFolder + "/SHMessage");
copyAssetFolder (getAssets(), "src/XSMessage", aResFolder + "/XSMessage");
// C++ runtime
loadLibVerbose ("gnustl_shared", aLoaded, aFailed);
@@ -204,6 +201,9 @@ public class OcctJniActivity extends Activity implements OnClickListener
String aDataPath = aDataUrl != null ? aDataUrl.getPath() : "";
myOcctView.open (aDataPath);
myLastPath = aDataPath;
myContext = new android.content.ContextWrapper (this);
myContext.getExternalFilesDir (null);
}
//! Handle scroll events
@@ -513,6 +513,9 @@ public class OcctJniActivity extends Activity implements OnClickListener
aClickedBtn.setBackgroundColor (getResources().getColor(R.color.pressedBtnColor));
if (myFileOpenDialog == null)
{
// should be requested on runtime since API level 26 (Android 8)
askUserPermission (android.Manifest.permission.WRITE_EXTERNAL_STORAGE, null); // for accessing SD card
myFileOpenDialog = new OcctJniFileDialog (this, aPath);
myFileOpenDialog.setFileEndsWith (".brep");
myFileOpenDialog.setFileEndsWith (".rle");
@@ -760,6 +763,88 @@ public class OcctJniActivity extends Activity implements OnClickListener
return aResultSize;
}
//! Request user permission.
private void askUserPermission (String thePermission, String theRationale)
{
// Dynamically load methods introduced by API level 23.
// On older system this permission is granted by user during application installation.
java.lang.reflect.Method aMetPtrCheckSelfPermission, aMetPtrRequestPermissions, aMetPtrShouldShowRequestPermissionRationale;
try
{
aMetPtrCheckSelfPermission = myContext.getClass().getMethod ("checkSelfPermission", String.class);
aMetPtrRequestPermissions = getClass().getMethod ("requestPermissions", String[].class, int.class);
aMetPtrShouldShowRequestPermissionRationale = getClass().getMethod ("shouldShowRequestPermissionRationale", String.class);
}
catch (SecurityException theError)
{
postMessage ("Unable to find permission methods:\n" + theError.getMessage(), Message_Trace);
return;
}
catch (NoSuchMethodException theError)
{
postMessage ("Unable to find permission methods:\n" + theError.getMessage(), Message_Trace);
return;
}
try
{
int isAlreadyGranted = (Integer )aMetPtrCheckSelfPermission.invoke (myContext, thePermission);
if (isAlreadyGranted == android.content.pm.PackageManager.PERMISSION_GRANTED)
{
return;
}
boolean toShowInfo = theRationale != null && (Boolean )aMetPtrShouldShowRequestPermissionRationale.invoke (this, thePermission);
if (toShowInfo)
{
postMessage (theRationale, Message_Info);
}
// show dialog to user
aMetPtrRequestPermissions.invoke (this, new String[]{thePermission}, 0);
}
catch (IllegalArgumentException theError)
{
postMessage ("Internal error: Unable to call permission method:\n" + theError.getMessage(), Message_Fail);
return;
}
catch (IllegalAccessException theError)
{
postMessage ("Internal error: Unable to call permission method:\n" + theError.getMessage(), Message_Fail);
return;
}
catch (java.lang.reflect.InvocationTargetException theError)
{
postMessage ("Internal error: Unable to call permission method:\n" + theError.getMessage(), Message_Fail);
return;
}
}
//! Message gravity.
private static final int Message_Trace = 0;
private static final int Message_Info = 1;
private static final int Message_Warning = 2;
private static final int Message_Alarm = 3;
private static final int Message_Fail = 4;
//! Auxiliary method to show info message.
public void postMessage (String theMessage, int theGravity)
{
if (theGravity == Message_Trace)
{
return;
}
final String aText = theMessage;
final Context aCtx = this;
this.runOnUiThread (new Runnable() { public void run() {
android.app.AlertDialog.Builder aBuilder = new android.app.AlertDialog.Builder (aCtx);
aBuilder.setMessage (aText).setNegativeButton ("OK", null);
android.app.AlertDialog aDialog = aBuilder.create();
aDialog.show();
}});
}
//! OCCT major version
private native long cppOcctMajorVersion();
@@ -772,6 +857,7 @@ public class OcctJniActivity extends Activity implements OnClickListener
private OcctJniView myOcctView;
private TextView myMessageTextView;
private String myLastPath;
private android.content.ContextWrapper myContext = null;
private OcctJniFileDialog myFileOpenDialog;
private int myButtonPreferSize = 65;

View File

@@ -34,11 +34,13 @@ public class OcctJniRenderer implements GLSurfaceView.Renderer
};
//! Empty constructor.
OcctJniRenderer()
OcctJniRenderer (GLSurfaceView theView,
float theScreenDensity)
{
myView = theView; // this makes cyclic dependency, but it is OK for JVM
if (OcctJniActivity.areNativeLoaded)
{
myCppViewer = cppCreate();
myCppViewer = cppCreate (theScreenDensity);
}
}
@@ -56,7 +58,10 @@ public class OcctJniRenderer implements GLSurfaceView.Renderer
{
if (myCppViewer != 0)
{
cppRedraw (myCppViewer);
if (cppRedraw (myCppViewer))
{
myView.requestRender(); // this method is allowed from any thread
}
}
}
@@ -77,48 +82,39 @@ public class OcctJniRenderer implements GLSurfaceView.Renderer
}
}
//! Initialize rotation (remember first point position)
public void onStartRotation (int theStartX, int theStartY)
//! Add touch point.
public void onAddTouchPoint (int theId, float theX, float theY)
{
if (myCppViewer != 0)
{
cppStartRotation (myCppViewer, theStartX, theStartY);
cppAddTouchPoint (myCppViewer, theId, theX, theY);
}
}
//! Perform rotation (relative to first point)
public void onRotation (int theX, int theY)
//! Update touch point.
public void onUpdateTouchPoint (int theId, float theX, float theY)
{
if (myCppViewer != 0)
{
cppOnRotation (myCppViewer, theX, theY);
cppUpdateTouchPoint (myCppViewer, theId, theX, theY);
}
}
//! Perform panning
public void onPanning (int theDX, int theDY)
//! Remove touch point.
public void onRemoveTouchPoint (int theId)
{
if (myCppViewer != 0)
{
cppOnPanning (myCppViewer, theDX, theDY);
cppRemoveTouchPoint (myCppViewer, theId);
}
}
//! Perform selection
public void onClick (int theX, int theY)
//! Select in 3D Viewer.
public void onSelectInViewer (float theX, float theY)
{
if (myCppViewer != 0)
{
cppOnClick (myCppViewer, theX, theY);
}
}
//! Stop previously active action (e.g. discard first rotation point)
public void onStopAction()
{
if (myCppViewer != 0)
{
cppStopAction (myCppViewer);
cppSelectInViewer (myCppViewer, theX, theY);
}
}
@@ -157,7 +153,7 @@ public class OcctJniRenderer implements GLSurfaceView.Renderer
}
//! Create instance of C++ class
private native long cppCreate();
private native long cppCreate (float theDispDensity);
//! Destroy instance of C++ class
private native void cppDestroy (long theCppPtr);
@@ -171,11 +167,21 @@ public class OcctJniRenderer implements GLSurfaceView.Renderer
//! Open CAD file
private native void cppOpen (long theCppPtr, String thePath);
//! Handle detection in the viewer
private native void cppMoveTo (long theCppPtr, int theX, int theY);
//! Add touch point
private native void cppAddTouchPoint (long theCppPtr, int theId, float theX, float theY);
//! Update touch point
private native void cppUpdateTouchPoint (long theCppPtr, int theId, float theX, float theY);
//! Remove touch point
private native void cppRemoveTouchPoint (long theCppPtr, int theId);
//! Select in 3D Viewer.
private native void cppSelectInViewer (long theCppPtr, float theX, float theY);
//! Redraw OCCT viewer
private native void cppRedraw (long theCppPtr);
//! Returns TRUE if more frames are requested.
private native boolean cppRedraw (long theCppPtr);
//! Fit All
private native void cppFitAll (long theCppPtr);
@@ -198,21 +204,7 @@ public class OcctJniRenderer implements GLSurfaceView.Renderer
//! Move camera
private native void cppSetZnegProj (long theCppPtr);
//! Initialize rotation
private native void cppStartRotation (long theCppPtr, int theStartX, int theStartY);
//! Perform rotation
private native void cppOnRotation (long theCppPtr, int theX, int theY);
//! Perform panning
private native void cppOnPanning (long theCppPtr, int theDX, int theDY);
//! Perform selection
private native void cppOnClick (long theCppPtr, int theX, int theY);
//! Stop action (rotation / panning / scaling)
private native void cppStopAction (long theCppPtr);
private GLSurfaceView myView = null; //!< back reference to the View
private long myCppViewer = 0; //!< pointer to c++ class instance
}

View File

@@ -38,6 +38,9 @@ class OcctJniView extends GLSurfaceView
{
super (theContext, theAttrs);
android.util.DisplayMetrics aDispInfo = theContext.getResources().getDisplayMetrics();
myScreenDensity = aDispInfo.density;
setPreserveEGLContextOnPause (true);
setEGLContextFactory (new ContextFactory());
setEGLConfigChooser (new ConfigChooser());
@@ -45,8 +48,9 @@ class OcctJniView extends GLSurfaceView
RelativeLayout.LayoutParams aLParams = new RelativeLayout.LayoutParams (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
aLParams.addRule (RelativeLayout.ALIGN_TOP);
myRenderer = new OcctJniRenderer();
myRenderer = new OcctJniRenderer (this, myScreenDensity);
setRenderer (myRenderer);
setRenderMode (GLSurfaceView.RENDERMODE_WHEN_DIRTY); // render on request to spare battery
}
//! Open file.
@@ -54,6 +58,7 @@ class OcctJniView extends GLSurfaceView
{
final String aPath = thePath;
queueEvent (new Runnable() { public void run() { myRenderer.open (aPath); }});
requestRender();
}
//! Create OpenGL ES 2.0+ context
@@ -202,77 +207,44 @@ class OcctJniView extends GLSurfaceView
//! Callback to handle touch events
@Override public boolean onTouchEvent (MotionEvent theEvent)
{
int aPointerIndex = theEvent.getActionIndex();
int aPointerId = theEvent.getPointerId (aPointerIndex);
int aMaskedAction = theEvent.getActionMasked();
final int aMaskedAction = theEvent.getActionMasked();
switch (aMaskedAction)
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
{
PointF aPntLast = null;
if (myActivePointers.size() >= 1)
final int aPointerIndex = theEvent.getActionIndex();
final int aPointerId = theEvent.getPointerId (aPointerIndex);
final PointF aPnt = new PointF (theEvent.getX (aPointerIndex), theEvent.getY (aPointerIndex));
if (theEvent.getPointerCount() == 1)
{
aPntLast = myActivePointers.get (myActivePointers.keyAt (0));
}
final PointF aPnt = new PointF();
aPnt.x = theEvent.getX (aPointerIndex);
aPnt.y = theEvent.getY (aPointerIndex);
myActivePointers.put (aPointerId, aPnt);
switch (myActivePointers.size())
{
case 1:
{
final int aStartX = (int )aPnt.x;
final int aStartY = (int )aPnt.y;
queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});
break;
}
case 2:
{
myPanFrom.x = (aPntLast.x + aPnt.x) * 0.5f;
myPanFrom.y = (aPntLast.y + aPnt.y) * 0.5f;
break;
}
mySelectPoint = aPnt;
}
else
{
mySelectPoint = null;
}
queueEvent (new Runnable() { public void run() { myRenderer.onAddTouchPoint (aPointerId, aPnt.x, aPnt.y); }});
break;
}
case MotionEvent.ACTION_MOVE:
{
for (int aNbPointers = theEvent.getPointerCount(), aPntIter = 0; aPntIter < aNbPointers; ++aPntIter)
{
PointF aPnt = myActivePointers.get (theEvent.getPointerId (aPntIter));
if (aPnt != null)
{
aPnt.x = theEvent.getX (aPntIter);
aPnt.y = theEvent.getY (aPntIter);
}
final int aPointerId = theEvent.getPointerId (aPntIter);
final PointF aPnt = new PointF (theEvent.getX (aPntIter), theEvent.getY (aPntIter));
queueEvent (new Runnable() { public void run() { myRenderer.onUpdateTouchPoint (aPointerId, aPnt.x, aPnt.y); }});
}
switch (myActivePointers.size())
if (mySelectPoint != null)
{
case 1:
final float aTouchThreshold = 5.0f * myScreenDensity;
final int aPointerIndex = theEvent.getActionIndex();
final PointF aDelta = new PointF (theEvent.getX (aPointerIndex) - mySelectPoint.x, theEvent.getY (aPointerIndex) - mySelectPoint.y);
if (Math.abs (aDelta.x) > aTouchThreshold || Math.abs (aDelta.y) > aTouchThreshold)
{
PointF aPnt = myActivePointers.get (theEvent.getPointerId (0));
final int anX = (int )aPnt.x;
final int anY = (int )aPnt.y;
queueEvent (new Runnable() { public void run() { myRenderer.onRotation (anX, anY); }});
break;
}
case 2:
{
PointF aPnt1 = myActivePointers.get (myActivePointers.keyAt (0));
PointF aPnt2 = myActivePointers.get (myActivePointers.keyAt (1));
PointF aPntAver = new PointF ((aPnt1.x + aPnt2.x) * 0.5f,
(aPnt1.y + aPnt2.y) * 0.5f);
final int aDX = (int )(aPntAver.x - myPanFrom.x);
final int aDY = (int )(myPanFrom.y -aPntAver.y);
myPanFrom.x = aPntAver.x;
myPanFrom.y = aPntAver.y;
queueEvent (new Runnable() { public void run() { myRenderer.onPanning (aDX, aDY); }});
mySelectPoint = null;
}
}
break;
@@ -281,30 +253,21 @@ class OcctJniView extends GLSurfaceView
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
{
myActivePointers.remove (aPointerId);
if (myActivePointers.size() == 0)
if (mySelectPoint != null)
{
final int aPressX = (int )theEvent.getX (aPointerIndex);
final int aPressY = (int )theEvent.getY (aPointerIndex);
double aPressTimeMs = theEvent.getEventTime() - theEvent.getDownTime();
if (aPressTimeMs < 100.0)
{
queueEvent (new Runnable() { public void run() { myRenderer.onClick (aPressX, aPressY); }});
break;
}
final float aSelX = mySelectPoint.x;
final float aSelY = mySelectPoint.y;
queueEvent (new Runnable() { public void run() { myRenderer.onSelectInViewer (aSelX, aSelY); }});
mySelectPoint = null;
}
else if (myActivePointers.size() == 1)
{
PointF aPnt = myActivePointers.get (myActivePointers.keyAt (0));
final int aStartX = (int )aPnt.x;
final int aStartY = (int )aPnt.y;
queueEvent (new Runnable() { public void run() { myRenderer.onStartRotation (aStartX, aStartY); }});
}
//queueEvent (new Runnable() { public void run() { myRenderer.onStopAction(); }});
break;
final int aPointerIndex = theEvent.getActionIndex();
final int aPointerId = theEvent.getPointerId (aPointerIndex);
final PointF aPnt = new PointF (theEvent.getX (aPointerIndex), theEvent.getY (aPointerIndex));
queueEvent (new Runnable() { public void run() { myRenderer.onRemoveTouchPoint (aPointerId); }});
}
}
///invalidate();
requestRender();
return true;
}
@@ -312,21 +275,20 @@ class OcctJniView extends GLSurfaceView
public void fitAll()
{
queueEvent (new Runnable() { public void run() { myRenderer.fitAll(); }});
requestRender();
}
//! Move camera
public void setProj (final OcctJniRenderer.TypeOfOrientation theProj)
{
queueEvent (new Runnable() { public void run() { myRenderer.setProj (theProj); }});
requestRender();
}
//! OCCT viewer
private OcctJniRenderer myRenderer = null;
//! Touch events cache
private SparseArray<PointF> myActivePointers = new SparseArray<PointF>();
//! Starting point for panning event
private PointF myPanFrom = new PointF (0.0f, 0.0f);
private OcctJniRenderer myRenderer = null;
private int mySelectId = -1;
private PointF mySelectPoint = null;
private float myScreenDensity = 1.0f;
}

View File

@@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.4.1)
set(HEADER_FILES OcctJni_MsgPrinter.hxx OcctJni_Viewer.hxx)
set(SOURCE_FILES OcctJni_MsgPrinter.cxx OcctJni_Viewer.cxx)
set (anOcctLibs
TKernel TKMath TKG2d TKG3d TKGeomBase TKBRep TKGeomAlgo TKTopAlgo TKShHealing TKMesh
# exchange
TKPrim TKBO TKBool TKFillet TKOffset
TKXSBase
TKIGES
TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP
# OCCT Visualization
TKService TKHLR TKV3d TKOpenGl
)
set(aLibDeps "")
# OCCT libraries
include_directories(${OCCT_ROOT}/inc)
foreach(anOcctLib ${anOcctLibs})
add_library(lib_${anOcctLib} SHARED IMPORTED)
set_target_properties(lib_${anOcctLib} PROPERTIES IMPORTED_LOCATION ${OCCT_ROOT}/libs/${ANDROID_ABI}/lib${anOcctLib}.so)
list(APPEND aLibDeps lib_${anOcctLib})
endforeach()
# FreeType
add_library(lib_FreeType SHARED IMPORTED)
set_target_properties(lib_FreeType PROPERTIES IMPORTED_LOCATION ${FREETYPE_ROOT}/libs/${ANDROID_ABI}/libfreetype.so)
list(APPEND aLibDeps lib_FreeType)
# FreeImage - uncomment, if OCCT was built with FreeImage
#add_library(lib_FreeImage SHARED IMPORTED)
#set_target_properties(lib_FreeImage PROPERTIES IMPORTED_LOCATION ${FREETYPE_ROOT}/libs/${ANDROID_ABI}/libfreeimage.so)
#list(APPEND aLibDeps lib_FreeImage)
# system libraries
list(APPEND aLibDeps EGL GLESv2 log android)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -frtti -fexceptions -fpermissive")
add_library(TKJniSample SHARED ${SOURCE_FILES})
target_link_libraries(TKJniSample ${aLibDeps})

View File

@@ -11,7 +11,7 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <OcctJni_MsgPrinter.hxx>
#include "OcctJni_MsgPrinter.hxx"
#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>

View File

@@ -34,7 +34,7 @@ protected:
//! Main printing method
virtual void send (const TCollection_AsciiString& theString,
const Message_Gravity theGravity) const;
const Message_Gravity theGravity) const override;
private:

View File

@@ -11,17 +11,21 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <OcctJni_Viewer.hxx>
#include <OcctJni_MsgPrinter.hxx>
#include "OcctJni_Viewer.hxx"
#include "OcctJni_MsgPrinter.hxx"
#include <AIS_ViewCube.hxx>
#include <AIS_Shape.hxx>
#include <Aspect_NeutralWindow.hxx>
#include <Image_AlienPixMap.hxx>
#include <BRepTools.hxx>
#include <Message_Messenger.hxx>
#include <Message_MsgFile.hxx>
#include <Message_PrinterSystemLog.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <OSD_Environment.hxx>
#include <OSD_Timer.hxx>
#include <Prs3d_DatumAspect.hxx>
#include <Standard_Version.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
@@ -105,18 +109,69 @@ Standard_Boolean setResourceEnv (const TCollection_AsciiString& theVarName,
// function : OcctJni_Viewer
// purpose :
// =======================================================================
OcctJni_Viewer::OcctJni_Viewer()
OcctJni_Viewer::OcctJni_Viewer (float theDispDensity)
: myDevicePixelRatio (theDispDensity),
myIsJniMoreFrames (false)
{
SetTouchToleranceScale (theDispDensity);
#ifndef NDEBUG
// Register printer for logging messages into global Android log.
// Should never be used in production (or specify higher gravity for logging only failures).
Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
aMsgMgr->RemovePrinters (STANDARD_TYPE (Message_PrinterSystemLog));
aMsgMgr->AddPrinter (new Message_PrinterSystemLog ("OcctJni_Viewer"));
#endif
// prepare necessary environment
TCollection_AsciiString aResRoot = "/data/data/com.opencascade.jnisample/files";
setResourceEnv ("CSF_ShadersDirectory", aResRoot + "/Shaders", "Declarations.glsl", Standard_False);
setResourceEnv ("CSF_XSMessage", aResRoot + "/XSMessage", "XSTEP.us", Standard_False);
setResourceEnv ("CSF_SHMessage", aResRoot + "/XSMessage", "SHAPE.us", Standard_False);
//setResourceEnv ("CSF_PluginDefaults", "Plugin", Standard_False);
setResourceEnv ("CSF_XSMessage", aResRoot + "/XSMessage", "XSTEP.us", Standard_False);
setResourceEnv ("CSF_SHMessage", aResRoot + "/XSMessage", "SHAPE.us", Standard_False);
}
// make sure OCCT loads the dictionary
//UnitsAPI::SetLocalSystem (UnitsAPI_SI);
// ================================================================
// Function : dumpGlInfo
// Purpose :
// ================================================================
void OcctJni_Viewer::dumpGlInfo (bool theIsBasic)
{
TColStd_IndexedDataMapOfStringString aGlCapsDict;
myView->DiagnosticInformation (aGlCapsDict, Graphic3d_DiagnosticInfo_Basic); //theIsBasic ? Graphic3d_DiagnosticInfo_Basic : Graphic3d_DiagnosticInfo_Complete);
if (theIsBasic)
{
TCollection_AsciiString aViewport;
aGlCapsDict.FindFromKey ("Viewport", aViewport);
aGlCapsDict.Clear();
aGlCapsDict.Add ("Viewport", aViewport);
}
aGlCapsDict.Add ("Display scale", TCollection_AsciiString(myDevicePixelRatio));
// beautify output
{
TCollection_AsciiString* aGlVer = aGlCapsDict.ChangeSeek ("GLversion");
TCollection_AsciiString* aGlslVer = aGlCapsDict.ChangeSeek ("GLSLversion");
if (aGlVer != NULL
&& aGlslVer != NULL)
{
*aGlVer = *aGlVer + " [GLSL: " + *aGlslVer + "]";
aGlslVer->Clear();
}
}
TCollection_AsciiString anInfo;
for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aGlCapsDict); aValueIter.More(); aValueIter.Next())
{
if (!aValueIter.Value().IsEmpty())
{
if (!anInfo.IsEmpty())
{
anInfo += "\n";
}
anInfo += aValueIter.Key() + ": " + aValueIter.Value();
}
}
Message::Send (anInfo, Message_Warning);
}
// =======================================================================
@@ -152,19 +207,10 @@ bool OcctJni_Viewer::init()
return false;
}
TCollection_AsciiString anEglInfo = TCollection_AsciiString()
+ "\n EGLVersion: " + eglQueryString (anEglDisplay, EGL_VERSION)
+ "\n EGLVendor: " + eglQueryString (anEglDisplay, EGL_VENDOR)
+ "\n EGLClient APIs: " + eglQueryString (anEglDisplay, EGL_CLIENT_APIS)
+ "\n GLvendor: " + (const char* )glGetString (GL_VENDOR)
+ "\n GLdevice: " + (const char* )glGetString (GL_RENDERER)
+ "\n GLversion: " + (const char* )glGetString (GL_VERSION) + " [GLSL: " + (const char* )glGetString (GL_SHADING_LANGUAGE_VERSION) + "]";
::Message::DefaultMessenger()->Send (anEglInfo, Message_Info);
if (!myViewer.IsNull())
{
Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
Handle(OcctJni_Window) aWindow = Handle(OcctJni_Window)::DownCast (myView->Window());
Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast (myView->Window());
if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
{
Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized!", Message_Fail);
@@ -174,6 +220,7 @@ bool OcctJni_Viewer::init()
aWindow->SetSize (aWidth, aHeight);
myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
dumpGlInfo (true);
return true;
}
@@ -187,6 +234,17 @@ bool OcctJni_Viewer::init()
return false;
}
myTextStyle = new Prs3d_TextAspect();
myTextStyle->SetFont (Font_NOF_ASCII_MONO);
myTextStyle->SetHeight (12);
myTextStyle->Aspect()->SetColor (Quantity_NOC_GRAY95);
myTextStyle->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK);
myTextStyle->Aspect()->SetDisplayType (Aspect_TODT_SHADOW);
myTextStyle->Aspect()->SetTextFontAspect (Font_FA_Bold);
myTextStyle->Aspect()->SetTextZoomable (false);
myTextStyle->SetHorizontalJustification (Graphic3d_HTA_LEFT);
myTextStyle->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
// create viewer
myViewer = new V3d_Viewer (aDriver);
myViewer->SetDefaultBackgroundColor (Quantity_NOC_BLACK);
@@ -195,14 +253,22 @@ bool OcctJni_Viewer::init()
// create AIS context
myContext = new AIS_InteractiveContext (myViewer);
//myContext->SetDisplayMode (AIS_WireFrame, false);
myContext->SetPixelTolerance (int(myDevicePixelRatio * 6.0)); // increase tolerance and adjust to hi-dpi screens
myContext->SetDisplayMode (AIS_Shaded, false);
Handle(OcctJni_Window) aWindow = new OcctJni_Window (aWidth, aHeight);
Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
aWindow->SetSize (aWidth, aHeight);
myView = myViewer->CreateView();
myView->SetImmediateUpdate (false);
myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
myView->ChangeRenderingParams().ToShowStats = true;
myView->ChangeRenderingParams().CollectedStats = (Graphic3d_RenderingParams::PerfCounters ) (Graphic3d_RenderingParams::PerfCounters_FrameRate | Graphic3d_RenderingParams::PerfCounters_Triangles);
myView->ChangeRenderingParams().StatsTextAspect = myTextStyle->Aspect();
myView->ChangeRenderingParams().StatsTextHeight = (int )myTextStyle->Height();
myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
myView->TriedronDisplay (Aspect_TOTP_RIGHT_LOWER, Quantity_NOC_WHITE, 0.08, V3d_ZBUFFER);
dumpGlInfo (false);
//myView->TriedronDisplay (Aspect_TOTP_RIGHT_LOWER, Quantity_NOC_WHITE, 0.08 * myDevicePixelRatio, V3d_ZBUFFER);
initContent();
return true;
@@ -233,13 +299,13 @@ void OcctJni_Viewer::resize (int theWidth,
}
Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
Handle(OcctJni_Window) aWindow = Handle(OcctJni_Window)::DownCast (myView->Window());
Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast (myView->Window());
aWindow->SetSize (theWidth, theHeight);
//myView->MustBeResized(); // can be used instead of SetWindow() when EGLsurface has not been changed
EGLContext anEglContext = eglGetCurrentContext();
myView->SetImmediateUpdate (Standard_False);
myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
dumpGlInfo (true);
//saveSnapshot ("/sdcard/Download/tt.png", theWidth, theHeight);
}
@@ -251,6 +317,28 @@ void OcctJni_Viewer::initContent()
{
myContext->RemoveAll (Standard_False);
if (myViewCube.IsNull())
{
myViewCube = new AIS_ViewCube();
{
// setup view cube size
static const double THE_CUBE_SIZE = 60.0;
myViewCube->SetSize (myDevicePixelRatio * THE_CUBE_SIZE, false);
myViewCube->SetBoxFacetExtension (myViewCube->Size() * 0.15);
myViewCube->SetAxesPadding (myViewCube->Size() * 0.10);
myViewCube->SetFontHeight (THE_CUBE_SIZE * 0.16);
}
// presentation parameters
myViewCube->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_RIGHT_LOWER, Graphic3d_Vec2i (200, 200)));
myViewCube->Attributes()->SetDatumAspect (new Prs3d_DatumAspect());
myViewCube->Attributes()->DatumAspect()->SetTextAspect (myTextStyle);
// animation parameters
myViewCube->SetViewAnimation (myViewAnimation);
myViewCube->SetFixedAnimationLoop (false);
myViewCube->SetAutoStartAnimation (true);
}
myContext->Display (myViewCube, false);
OSD_Timer aTimer;
aTimer.Start();
if (!myShape.IsNull())
@@ -383,6 +471,10 @@ bool OcctJni_Viewer::open (const TCollection_AsciiString& thePath)
if (!myContext.IsNull())
{
myContext->RemoveAll (Standard_False);
if (!myViewCube.IsNull())
{
myContext->Display (myViewCube, false);
}
}
if (thePath.IsEmpty())
{
@@ -523,18 +615,33 @@ bool OcctJni_Viewer::saveSnapshot (const TCollection_AsciiString& thePath,
return true;
}
// ================================================================
// Function : handleViewRedraw
// Purpose :
// ================================================================
void OcctJni_Viewer::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView)
{
AIS_ViewController::handleViewRedraw (theCtx, theView);
myIsJniMoreFrames = myToAskNextFrame;
}
// =======================================================================
// function : redraw
// purpose :
// =======================================================================
void OcctJni_Viewer::redraw()
bool OcctJni_Viewer::redraw()
{
if (myView.IsNull())
{
return;
return false;
}
myView->Redraw();
// handle user input
myIsJniMoreFrames = false;
myView->InvalidateImmediate();
FlushViewEvents (myContext, myView, true);
return myIsJniMoreFrames;
}
// =======================================================================
@@ -552,89 +659,13 @@ void OcctJni_Viewer::fitAll()
myView->Invalidate();
}
// =======================================================================
// function : startRotation
// purpose :
// =======================================================================
void OcctJni_Viewer::startRotation (int theStartX,
int theStartY)
{
if (myView.IsNull())
{
return;
}
myView->StartRotation (theStartX, theStartY, 0.45);
myView->Invalidate();
}
// =======================================================================
// function : onRotation
// purpose :
// =======================================================================
void OcctJni_Viewer::onRotation (int theX,
int theY)
{
if (myView.IsNull())
{
return;
}
myView->Rotation (theX, theY);
myView->Invalidate();
}
// =======================================================================
// function : onPanning
// purpose :
// =======================================================================
void OcctJni_Viewer::onPanning (int theDX,
int theDY)
{
if (myView.IsNull())
{
return;
}
myView->Pan (theDX, theDY);
myView->Invalidate();
}
// =======================================================================
// function : onClick
// purpose :
// =======================================================================
void OcctJni_Viewer::onClick (int theX,
int theY)
{
if (myView.IsNull())
{
return;
}
myContext->MoveTo (theX, theY, myView, Standard_False);
myContext->Select (Standard_False);
myView->Invalidate();
}
// =======================================================================
// function : stopAction
// purpose :
// =======================================================================
void OcctJni_Viewer::stopAction()
{
if (myView.IsNull())
{
return;
}
}
#define jexp extern "C" JNIEXPORT
jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppCreate (JNIEnv* theEnv,
jobject theObj)
jobject theObj,
jfloat theDispDensity)
{
return jlong(new OcctJni_Viewer());
return jlong(new OcctJni_Viewer (theDispDensity));
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppDestroy (JNIEnv* theEnv,
@@ -684,11 +715,11 @@ jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOpen (JNIEnv
((OcctJni_Viewer* )theCppPtr)->open (aPath);
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRedraw (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr)
jexp jboolean JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRedraw (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr)
{
((OcctJni_Viewer* )theCppPtr)->redraw();
return ((OcctJni_Viewer* )theCppPtr)->redraw() ? JNI_TRUE : JNI_FALSE;
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetAxoProj (JNIEnv* theEnv,
@@ -747,47 +778,41 @@ jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppFitAll (JNIE
((OcctJni_Viewer* )theCppPtr)->fitAll();
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppStartRotation (JNIEnv* theEnv,
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppAddTouchPoint (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jint theStartX,
jint theStartY)
jint theId,
jfloat theX,
jfloat theY)
{
((OcctJni_Viewer* )theCppPtr)->startRotation (theStartX, theStartY);
((OcctJni_Viewer* )theCppPtr)->AddTouchPoint (theId, Graphic3d_Vec2d (theX, theY));
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOnRotation (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jint theX,
jint theY)
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppUpdateTouchPoint (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jint theId,
jfloat theX,
jfloat theY)
{
((OcctJni_Viewer* )theCppPtr)->onRotation (theX, theY);
((OcctJni_Viewer* )theCppPtr)->UpdateTouchPoint (theId, Graphic3d_Vec2d (theX, theY));
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOnPanning (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jint theDX,
jint theDY)
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRemoveTouchPoint (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jint theId)
{
((OcctJni_Viewer* )theCppPtr)->onPanning (theDX, theDY);
((OcctJni_Viewer* )theCppPtr)->RemoveTouchPoint (theId);
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOnClick (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jint theX,
jint theY)
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSelectInViewer (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr,
jfloat theX,
jfloat theY)
{
((OcctJni_Viewer* )theCppPtr)->onClick (theX, theY);
}
jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppStopAction (JNIEnv* theEnv,
jobject theObj,
jlong theCppPtr)
{
((OcctJni_Viewer* )theCppPtr)->stopAction();
((OcctJni_Viewer* )theCppPtr)->SelectInViewer (Graphic3d_Vec2i ((int )theX, (int )theY));
}
jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMajorVersion (JNIEnv* theEnv,

View File

@@ -11,21 +11,22 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <OcctJni_Window.hxx>
#include <AIS_InteractiveContext.hxx>
#include <AIS_ViewController.hxx>
#include <TopoDS_Shape.hxx>
#include <V3d_Viewer.hxx>
#include <V3d_View.hxx>
class AIS_ViewCube;
//! Main C++ back-end for activity.
class OcctJni_Viewer
class OcctJni_Viewer : public AIS_ViewController
{
public:
//! Empty constructor
OcctJni_Viewer();
OcctJni_Viewer (float theDispDensity);
//! Initialize the viewer
bool init();
@@ -46,43 +47,45 @@ public:
int theHeight = 0);
//! Viewer update.
void redraw();
//! Returns TRUE if more frames should be requested.
bool redraw();
//! Move camera
void setProj (V3d_TypeOfOrientation theProj) { if (!myView.IsNull()) myView->SetProj (theProj); }
void setProj (V3d_TypeOfOrientation theProj)
{
if (myView.IsNull())
{
return;
}
myView->SetProj (theProj);
myView->Invalidate();
}
//! Fit All.
void fitAll();
//! Start rotation (remember first point position)
void startRotation (int theStartX,
int theStartY);
//! Perform rotation (relative to first point)
void onRotation (int theX,
int theY);
//! Perform panning
void onPanning (int theDX,
int theDY);
//! Perform selection
void onClick (int theX,
int theY);
//! Stop previously started action
void stopAction();
protected:
//! Reset viewer content.
void initContent();
//! Print information about OpenGL ES context.
void dumpGlInfo (bool theIsBasic);
//! Handle redraw.
virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView) override;
protected:
Handle(V3d_Viewer) myViewer;
Handle(V3d_View) myView;
Handle(AIS_InteractiveContext) myContext;
Handle(Prs3d_TextAspect) myTextStyle; //!< text style for OSD elements
Handle(AIS_ViewCube) myViewCube; //!< view cube object
TopoDS_Shape myShape;
float myDevicePixelRatio; //!< device pixel ratio for handling high DPI displays
bool myIsJniMoreFrames; //!< need more frame flag
};

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1002 B

After

Width:  |  Height:  |  Size: 1002 B

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

View File

Before

Width:  |  Height:  |  Size: 917 B

After

Width:  |  Height:  |  Size: 917 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 839 B

After

Width:  |  Height:  |  Size: 839 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,17 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
}
}
allprojects {
repositories {
jcenter()
google()
}
}

View File

@@ -0,0 +1,5 @@
# customized paths
OCCT_ROOT=c\:/android/occt-dev-android
FREETYPE_ROOT=c\:/android/freetype-2.7.1-android
# in case if OCCT was built with FreeImage
#FREEIMAGE_ROOT=c\:/android/freeimage-3.17-android

View File

@@ -1,205 +0,0 @@
LOCAL_PATH:= $(call my-dir)
STL_INC := $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/include $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/libs/$(TARGET_ARCH_ABI)/include
#STL_LIB := $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/libs/$(TARGET_ARCH_ABI)/libgnustl_static.a
STL_LIB := $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/$(NDK_TOOLCHAIN_VERSION)/libs/$(TARGET_ARCH_ABI)/libgnustl_shared.so
OCCT_ROOT := $(LOCAL_PATH)/../../../..
FREETYPE_INC := $(OCCT_ROOT)/../freetype/include/freetype2
FREETYPE_LIBS := $(OCCT_ROOT)/../freetype/libs
FREEIMAGE_INC := $(OCCT_ROOT)/../FreeImage/include
FREEIMAGE_LIBS := $(OCCT_ROOT)/../FreeImage/libs
OCCT_INC := $(OCCT_ROOT)/inc
OCCT_LIBS := $(OCCT_ROOT)/and/libs
ASSETDIR := $(LOCAL_PATH)/../assets
$(ASSETDIR)/Shaders: $(ASSETDIR)
-mkdir -p $(ASSETDIR)
-mkdir -p $(ASSETDIR)/Shaders
cp -f -r $(OCCT_ROOT)/src/Shaders/*.* $(ASSETDIR)/Shaders
$(ASSETDIR)/SHMessage: $(ASSETDIR)
-mkdir -p $(ASSETDIR)
-mkdir -p $(ASSETDIR)/SHMessage
cp -f -r $(OCCT_ROOT)/src/SHMessage/*.* $(ASSETDIR)/SHMessage
$(ASSETDIR)/XSMessage: $(ASSETDIR)
-mkdir -p $(ASSETDIR)
-mkdir -p $(ASSETDIR)/XSMessage
cp -f -r $(OCCT_ROOT)/src/XSMessage/*.* $(ASSETDIR)/XSMessage
pre_all: $(ASSETDIR)/Shaders $(ASSETDIR)/SHMessage $(ASSETDIR)/XSMessage
jniall: pre_all all
# STL libs
include $(CLEAR_VARS)
LOCAL_MODULE := SharedStl
LOCAL_EXPORT_C_INCLUDES := $(STL_INC)
LOCAL_SRC_FILES := $(STL_LIB)
include $(PREBUILT_SHARED_LIBRARY)
# 3rd-parties used in OCCT
include $(CLEAR_VARS)
LOCAL_MODULE := FreeType
LOCAL_EXPORT_C_INCLUDES := $(FREETYPE_INC)
LOCAL_SRC_FILES := $(FREETYPE_LIBS)/$(TARGET_ARCH_ABI)/libfreetype.so
include $(PREBUILT_SHARED_LIBRARY)
#include $(CLEAR_VARS)
#LOCAL_MODULE := FreeImage
#LOCAL_EXPORT_C_INCLUDES := $(FREEIMAGE_INC)
#LOCAL_SRC_FILES := $(FREEIMAGE_LIBS)/$(TARGET_ARCH_ABI)/libfreeimage.so
#include $(PREBUILT_SHARED_LIBRARY)
# OCCT core
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKernel
LOCAL_EXPORT_C_INCLUDES := $(OCCT_INC)
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKernel.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKMath
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKMath.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKG2d
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKG2d.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKG3d
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKG3d.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKGeomBase
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKGeomBase.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKBRep
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKBRep.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKGeomAlgo
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKGeomAlgo.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKTopAlgo
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKTopAlgo.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKShHealing
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKShHealing.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKMesh
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKMesh.so
include $(PREBUILT_SHARED_LIBRARY)
# OCCT Exchange
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKPrim
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKPrim.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKBO
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKBO.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKBool
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKBool.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKFillet
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKFillet.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKOffset
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKOffset.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKXSBase
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKXSBase.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKIGES
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKIGES.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKSTEPBase
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEPBase.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKSTEPAttr
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEPAttr.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKSTEP209
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEP209.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKSTEP
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKSTEP.so
include $(PREBUILT_SHARED_LIBRARY)
# OCCT visualization
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKService
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKService.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKHLR
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKHLR.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKV3d
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKV3d.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := OcctTKOpenGl
LOCAL_SRC_FILES := $(OCCT_LIBS)/$(TARGET_ARCH_ABI)/libTKOpenGl.so
include $(PREBUILT_SHARED_LIBRARY)
# our sample
include $(CLEAR_VARS)
LOCAL_MODULE := libTKJniSample
LOCAL_C_INCLUDES := $(STL_INC)
#LOCAL_STATIC_LIBRARIES := $(STL_LIB) does not work
LOCAL_CFLAGS := -Wall -std=c++11
LOCAL_CPP_EXTENSION := .cxx .cpp
LOCAL_CPP_FEATURES := rtti exceptions
LOCAL_SRC_FILES := OcctJni_Viewer.cxx OcctJni_Window.cxx OcctJni_MsgPrinter.cxx
LOCAL_SHARED_LIBRARIES := OcctTKernel OcctTKMath OcctTKG2d OcctTKG3d OcctTKGeomBase OcctTKBRep OcctTKGeomAlgo OcctTKTopAlgo OcctTKShHealing OcctTKMesh OcctTKPrim
LOCAL_SHARED_LIBRARIES += OcctTKIGES OcctTKSTEP OcctTKXSBase
LOCAL_SHARED_LIBRARIES += OcctTKService OcctTKHLR OcctTKV3d OcctTKOpenGl
LOCAL_SHARED_LIBRARIES += SharedStl
LOCAL_LDLIBS := -llog -lGLESv2 -lEGL
#LOCAL_LDLIBS += $(STL_LIB)
include $(BUILD_SHARED_LIBRARY)

View File

@@ -1,8 +0,0 @@
NDK_TOOLCHAIN_VERSION := 4.8
APP_PLATFORM := android-15
APP_ABI := armeabi-v7a
#APP_ABI := all
#APP_STL := gnustl_static
#APP_STL := stlport_static

View File

@@ -1,109 +0,0 @@
// Copyright (c) 2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef OcctJni_Window_H
#define OcctJni_Window_H
#include <Aspect_Window.hxx>
//! This class defines dummy window
class OcctJni_Window : public Aspect_Window
{
public:
//! Creates a wrapper over existing Window handle
OcctJni_Window (const int theWidth, const int theHeight)
: myWidth (theWidth), myHeight(theHeight) {}
//! Returns native Window handle
virtual Aspect_Drawable NativeHandle() const Standard_OVERRIDE { return 0; }
//! Returns parent of native Window handle
virtual Aspect_Drawable NativeParentHandle() const Standard_OVERRIDE { return 0; }
//! Returns nothing on Android
virtual Aspect_FBConfig NativeFBConfig() const Standard_OVERRIDE { return 0; }
virtual void Destroy() {}
//! Opens the window <me>
virtual void Map() const Standard_OVERRIDE {}
//! Closes the window <me>
virtual void Unmap() const Standard_OVERRIDE {}
//! Applies the resizing to the window <me>
virtual Aspect_TypeOfResize DoResize() Standard_OVERRIDE { return Aspect_TOR_UNKNOWN; }
//! Apply the mapping change to the window <me>
virtual Standard_Boolean DoMapping() const Standard_OVERRIDE { return Standard_True; }
//! Returns True if the window <me> is opened
virtual Standard_Boolean IsMapped() const Standard_OVERRIDE { return Standard_True; }
//! Returns The Window RATIO equal to the physical WIDTH/HEIGHT dimensions
virtual Standard_Real Ratio() const Standard_OVERRIDE { return 1.0; }
//! Returns The Window POSITION in PIXEL
virtual void Position (Standard_Integer& theX1,
Standard_Integer& theY1,
Standard_Integer& theX2,
Standard_Integer& theY2) const Standard_OVERRIDE
{
theX1 = 0;
theX2 = myWidth;
theY1 = 0;
theY2 = myHeight;
}
//! Set The Window POSITION in PIXEL
void SetPosition (const Standard_Integer theX1,
const Standard_Integer theY1,
const Standard_Integer theX2,
const Standard_Integer theY2)
{
myWidth = theX2 - theX1;
myHeight = theY2 - theY1;
}
//! Returns The Window SIZE in PIXEL
virtual void Size (Standard_Integer& theWidth,
Standard_Integer& theHeight) const Standard_OVERRIDE
{
theWidth = myWidth;
theHeight = myHeight;
}
//! Set The Window SIZE in PIXEL
void SetSize (const Standard_Integer theWidth,
const Standard_Integer theHeight)
{
myWidth = theWidth;
myHeight = theHeight;
}
private:
int myWidth;
int myHeight;
public:
DEFINE_STANDARD_RTTIEXT(OcctJni_Window,Aspect_Window)
};
DEFINE_STANDARD_HANDLE(OcctJni_Window, Aspect_Window)
#endif // OcctJni_Window_H

View File

@@ -1,14 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-15

View File

@@ -0,0 +1 @@
include ':app'

View File

@@ -10,19 +10,15 @@ set (Animation_HEADER_FILES ${Animation_SRC_DIR}/AnimationApp.h
${Animation_SRC_DIR}/AnimationDoc.h
${Animation_SRC_DIR}/AnimationView3D.h
${Animation_SRC_DIR}/Fonc.hxx
${Animation_SRC_DIR}/Sensitivity.h
${Animation_SRC_DIR}/ShadingDialog.h
${Animation_SRC_DIR}/ThreadDialog.h
${Animation_SRC_DIR}/Tune.h
${Animation_SRC_DIR}/StdAfx.h )
set (Animation_SOURCE_FILES ${Animation_SRC_DIR}/AnimationApp.cpp
${Animation_SRC_DIR}/AnimationDoc.cpp
${Animation_SRC_DIR}/AnimationView3D.cpp
${Animation_SRC_DIR}/Fonc.cxx
${Animation_SRC_DIR}/Sensitivity.cpp
${Animation_SRC_DIR}/ShadingDialog.cpp
${Animation_SRC_DIR}/ThreadDialog.cpp
${Animation_SRC_DIR}/Tune.cpp
${Animation_SRC_DIR}/StdAfx.cpp )
set (Animation_RESOURCE_DIR ${MFC_STANDARD_SAMPLES_DIR}/09_Animation/res)

View File

@@ -314,7 +314,6 @@
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\..\src\Fonc.cxx" />
<ClCompile Include="..\..\..\src\Sensitivity.cpp" />
<ClCompile Include="..\..\..\src\ShadingDialog.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -367,7 +366,6 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\..\..\src\Tune.cpp" />
<ClCompile Include="..\..\..\..\Common\WINMAIN.CPP">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -391,11 +389,9 @@
<ClInclude Include="..\..\..\src\AnimationView3D.h" />
<ClInclude Include="..\..\..\src\Fonc.hxx" />
<ClInclude Include="..\..\..\res\resource.h" />
<ClInclude Include="..\..\..\src\Sensitivity.h" />
<ClInclude Include="..\..\..\src\ShadingDialog.h" />
<ClInclude Include="..\..\..\src\StdAfx.h" />
<ClInclude Include="..\..\..\src\ThreadDialog.h" />
<ClInclude Include="..\..\..\src\Tune.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\res\child2.bmp" />

View File

@@ -32,9 +32,6 @@
<ClCompile Include="..\..\..\src\Fonc.cxx">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\Sensitivity.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\ShadingDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -44,9 +41,6 @@
<ClCompile Include="..\..\..\src\ThreadDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\Tune.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\Common\WINMAIN.CPP">
<Filter>Source Files</Filter>
</ClCompile>
@@ -67,9 +61,6 @@
<ClInclude Include="..\..\..\res\resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\Sensitivity.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\ShadingDialog.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -79,9 +70,6 @@
<ClInclude Include="..\..\..\src\ThreadDialog.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\Tune.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\res\child2.bmp">

View File

@@ -80,9 +80,6 @@ BEGIN
BUTTON ID_SHADING
SEPARATOR
BUTTON ID_FILE_LOADGRID
BUTTON ID_SENSITIVITY
BUTTON ID_VIEW_DISPLAYSTATUS
BUTTON ID_WALK_WALKTHRU
SEPARATOR
BUTTON ID_APP_ABOUT
END
@@ -156,11 +153,6 @@ BEGIN
BEGIN
MENUITEM "&About DisplayAnimation...", ID_APP_ABOUT
END
POPUP "Walk"
BEGIN
MENUITEM "Sensitivity...", ID_SENSITIVITY
MENUITEM "Walkthrough", ID_WALK_WALKTHRU
END
END
@@ -191,51 +183,6 @@ BEGIN
EDITTEXT IDC_Angle,65,27,48,16,ES_AUTOHSCROLL
END
IDD_SENS DIALOG 0, 0, 229, 50
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Sensitivity"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Fly",IDC_STATIC,8,10,10,8
EDITTEXT IDC_FLY,33,8,76,15,ES_AUTOHSCROLL
CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,112,8,11,15
LTEXT "Turn",IDC_STATIC,6,28,16,8
EDITTEXT IDC_TURN,34,25,76,15,ES_AUTOHSCROLL
CONTROL "Spin1",IDC_SPIN2,"msctls_updown32",UDS_ARROWKEYS,112,25,11,15
DEFPUSHBUTTON "OK",IDOK,170,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,170,23,50,14
END
IDD_TUNE DIALOG 0, 0, 131, 154
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Display Tuning"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Distance",IDC_STATIC,9,8,29,8
EDITTEXT IDC_FOCDIST,46,5,57,14,ES_AUTOHSCROLL
CONTROL "Spin1",IDC_SPINFOC,"msctls_updown32",UDS_ARROWKEYS,107,6,11,14
LTEXT "Aperture",IDC_STATIC,9,25,28,8
EDITTEXT IDC_APPERTURE,46,23,57,14,ES_AUTOHSCROLL
CONTROL "Spin4",IDC_SPINANG,"msctls_updown32",UDS_ARROWKEYS,107,23,11,14
LTEXT "X :",IDC_STATIC,17,52,12,8
LTEXT "0.",IDC_XEYE,31,52,66,8
GROUPBOX "Eye",IDC_STATIC,9,41,110,43
LTEXT "Y :",IDC_STATIC,17,62,12,8
LTEXT "0.",IDC_YEYE,31,62,66,8
LTEXT "Z :",IDC_STATIC,17,72,12,8
LTEXT "0.",IDC_ZEYE,31,72,66,8
LTEXT "X :",IDC_STATIC,15,98,12,8
LTEXT "0.",IDC_XAT,33,98,66,8
GROUPBOX "Target",IDC_STATIC,9,86,110,45
LTEXT "Y :",IDC_STATIC,15,109,12,8
LTEXT "0.",IDC_YAT,33,109,66,8
LTEXT "Z :",IDC_STATIC,15,120,12,8
LTEXT "0.",IDC_ZAT,33,120,66,8
LTEXT "Twist :",IDC_STATIC,11,137,22,8
LTEXT "0.",IDC_TWIST,35,137,77,8
END
/////////////////////////////////////////////////////////////////////////////
//
// Version
@@ -297,12 +244,6 @@ BEGIN
ID_FILE_LOADGRID "Load Grid Files\nLoad Grid File"
END
STRINGTABLE
BEGIN
ID_VIEW_DISPLAYSTATUS "Show/Hide the display status Window\nShow/Hide the display status Window"
ID_WALK_WALKTHRU "Toggle Walkthru On/Off\nToggle Walkthru On/Off"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////

View File

@@ -45,10 +45,6 @@ CAnimationDoc::CAnimationDoc()
{
// TODO: add one-time construction code here
static Standard_Integer StaticCount=1;
StaticCount++;
myCount = StaticCount;
Handle(Graphic3d_GraphicDriver) aGraphicDriver =
((CAnimationApp*)AfxGetApp())->GetGraphicDriver();
@@ -60,7 +56,6 @@ CAnimationDoc::CAnimationDoc()
myDeviation = 0.0008;
thread = 4;
myAngle = 0;
BRep_Builder B;
TopoDS_Shape CrankArm;
@@ -184,90 +179,6 @@ void CAnimationDoc::Dump(CDumpContext& dc) const
//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
void CAnimationDoc::DragEvent(const Standard_Integer x ,
const Standard_Integer y ,
const Standard_Integer TheState ,
const Handle(V3d_View)& aView )
{
// TheState == -1 button down
// TheState == 0 move
// TheState == 1 button up
static Standard_Integer theButtonDownX=0;
static Standard_Integer theButtonDownY=0;
if (TheState == -1)
{
theButtonDownX=x;
theButtonDownY=y;
}
if (TheState == 1)
myAISContext->Select (theButtonDownX, theButtonDownY, x, y, aView, Standard_True);
}
//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
void CAnimationDoc::InputEvent(const Standard_Integer /*x*/,
const Standard_Integer /*y*/,
const Handle(V3d_View)& /*aView*/ )
{
myAISContext->Select (Standard_True);
}
//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
void CAnimationDoc::MoveEvent(const Standard_Integer x ,
const Standard_Integer y ,
const Handle(V3d_View)& aView )
{
myAISContext->MoveTo (x, y, aView, Standard_True);
}
//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
void CAnimationDoc::ShiftMoveEvent(const Standard_Integer x ,
const Standard_Integer y ,
const Handle(V3d_View)& aView )
{
myAISContext->MoveTo (x, y, aView, Standard_True);
}
//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
void CAnimationDoc::ShiftDragEvent(const Standard_Integer x ,
const Standard_Integer y ,
const Standard_Integer TheState ,
const Handle(V3d_View)& aView )
{
static Standard_Integer theButtonDownX=0;
static Standard_Integer theButtonDownY=0;
if (TheState == -1)
{
theButtonDownX=x;
theButtonDownY=y;
}
if (TheState == 0)
myAISContext->ShiftSelect (theButtonDownX, theButtonDownY, x, y, aView, Standard_True);
}
//-----------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------
void CAnimationDoc::ShiftInputEvent(const Standard_Integer /*x*/,
const Standard_Integer /*y*/,
const Handle(V3d_View)& /*aView*/)
{
myAISContext->ShiftSelect (Standard_True);
}
//-----------------------------------------------------------------------------------------
//
@@ -278,7 +189,7 @@ void CAnimationDoc::Popup(const Standard_Integer /*x*/,
{
}
void CAnimationDoc::OnMyTimer()
void CAnimationDoc::OnMyTimer (double theTimeSec)
{
// TODO: Add your message handler code here and/or call default
@@ -287,9 +198,7 @@ void CAnimationDoc::OnMyTimer()
Standard_Real X;
gp_Ax1 Ax1(gp_Pnt(0,0,0),gp_Vec(0,0,1));
myAngle++;
angleA = thread*myAngle*M_PI/180;
angleA = thread * theTimeSec;
X = Sin(angleA)*3/8;
angleB = atan(X / Sqrt(-X * X + 1));
Standard_Real decal(25*0.6);
@@ -308,8 +217,6 @@ void CAnimationDoc::OnMyTimer()
gp_Trsf aPistonTrsf;
aPistonTrsf.SetTranslation(gp_Vec(-3*decal*(1-Cos(angleA))-8*decal*(1-Cos(angleB)),0,0));
myAISContext->SetLocation(myAisPiston,aPistonTrsf);
myAISContext->UpdateCurrentViewer();
}
void CAnimationDoc::OnShading()

View File

@@ -17,33 +17,6 @@
class CAnimationDoc : public OCC_BaseDoc
{
public:
void DragEvent (const Standard_Integer x,
const Standard_Integer y,
const Standard_Integer TheState,
const Handle(V3d_View)& aView);
void InputEvent (const Standard_Integer x,
const Standard_Integer y,
const Handle(V3d_View)& aView);
void MoveEvent (const Standard_Integer x,
const Standard_Integer y,
const Handle(V3d_View)& aView);
void ShiftMoveEvent (const Standard_Integer x,
const Standard_Integer y,
const Handle(V3d_View)& aView);
void ShiftDragEvent (const Standard_Integer x,
const Standard_Integer y,
const Standard_Integer TheState,
const Handle(V3d_View)& aView);
void ShiftInputEvent (const Standard_Integer x,
const Standard_Integer y,
const Handle(V3d_View)& aView);
void Popup (const Standard_Integer x,
const Standard_Integer y,
const Handle(V3d_View)& aView);
@@ -78,11 +51,9 @@ private:
Handle(AIS_Shape) myAisEngineBlock ;
Standard_Real myDeviation;
Standard_Integer myAngle;
public:
void OnMyTimer();
Standard_Integer myCount;
void OnMyTimer (double theTimeSec);
Standard_Integer thread;
double m_Xmin, m_Ymin, m_Zmin, m_Xmax, m_Ymax, m_Zmax;
BOOL m_bIsGridLoaded;

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,12 @@
#pragma once
#endif // _MSC_VER >= 1000
#include "Tune.h"
#include "AnimationDoc.h"
#include "..\..\Common\res\OCC_Resource.h"
#include <AIS_AnimationTimer.hxx>
#include <AIS_ViewController.hxx>
class AIS_RubberBand;
enum View3D_CurrentAction {
@@ -26,7 +28,7 @@ enum View3D_CurrentAction {
CurrentAction3d_Turn
};
class CAnimationView3D : public CView
class CAnimationView3D : public CView, public AIS_ViewController
{
protected: // create from serialization only
CAnimationView3D();
@@ -58,20 +60,10 @@ public:
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
void SetDimensions ();
void ReloadData();
CTune m_Tune;
void SetFocal (double theFocus, double theAngle);
void Fly (int x , int y);
void Turn (int x , int y);
void Roll (int x , int y);
void Twist (int x , int y);
protected:
double m_dAngle;
BOOL m_bShift;
int m_cx , m_cy ;
int m_curx , m_cury ;
// Generated message map functions
protected:
@@ -94,6 +86,7 @@ protected:
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnBUTTONZoomProg();
afx_msg void OnBUTTONZoomWin();
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
@@ -110,15 +103,11 @@ protected:
afx_msg void OnUpdateBUTTONRot(CCmdUI* pCmdUI);
afx_msg void OnChangeBackground();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnSensitivity();
afx_msg void OnBUTTONFly();
afx_msg void OnBUTTONTurn();
afx_msg void OnUpdateBUTTONFly(CCmdUI* pCmdUI);
afx_msg void OnUpdateBUTTONTurn(CCmdUI* pCmdUI);
afx_msg void OnViewDisplaystatus();
afx_msg void OnUpdateViewDisplaystatus(CCmdUI* pCmdUI);
//}}AFX_MSG
public :
@@ -131,26 +120,44 @@ private:
Handle(V3d_View) myView;
public:
Handle(V3d_View)& GetView() { return myView;};
void DisplayTuneDialog();
//! Request view redrawing.
void update3dView();
//! Flush events and redraw view.
void redraw3dView();
protected:
//! Handle view redraw.
virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView) Standard_OVERRIDE;
protected:
//! Setup mouse gestures.
void defineMouseGestures();
//! Get current action.
View3D_CurrentAction getCurrentAction() const { return myCurrentMode; }
//! Set current action.
void setCurrentAction (View3D_CurrentAction theAction)
{
myCurrentMode = theAction;
defineMouseGestures();
}
private:
Standard_Integer myXmin;
Standard_Integer myYmin;
Standard_Integer myXmax;
Standard_Integer myYmax;
AIS_AnimationTimer myAnimTimer;
AIS_MouseGestureMap myDefaultGestures;
Graphic3d_Vec2i myClickPos;
Standard_Real myCurZoom;
Standard_Boolean myHlrModeIsOn;
Standard_Boolean myIsTurnStarted;
unsigned int myUpdateRequests; //!< counter for unhandled update requests
View3D_CurrentAction myCurrentMode;
double m_Atx , m_Aty , m_Atz ;
double m_Eyex , m_Eyey , m_Eyez ;
double m_FlySens ;
double m_TurnSens ;
double m_Focus ;
private:
Handle(AIS_RubberBand) myRect; //!< Rubber rectangle for selection
void DrawRectangle (Standard_Integer theMinX, Standard_Integer theMinY, Standard_Integer theMaxX, Standard_Integer theMaxY,
Standard_Boolean theToDraw, Aspect_TypeOfLine theLineType = Aspect_TOL_SOLID);
};
#ifndef _DEBUG // debug version in AnimationView.cpp

View File

@@ -1,81 +0,0 @@
// Sensitivity.cpp : implementation file
//
#include "stdafx.h"
#include "Sensitivity.h"
#include "AnimationApp.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSensitivity dialog
CSensitivity::CSensitivity(CWnd* pParent /*=NULL*/)
: CDialog(CSensitivity::IDD, pParent)
{
//{{AFX_DATA_INIT(CSensitivity)
m_SensFly = 0.0;
m_SensTurn = 0.0;
//}}AFX_DATA_INIT
}
void CSensitivity::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSensitivity)
DDX_Text(pDX, IDC_FLY, m_SensFly);
DDV_MinMaxDouble(pDX, m_SensFly, 0., 10000000.);
DDX_Text(pDX, IDC_TURN, m_SensTurn);
DDV_MinMaxDouble(pDX, m_SensTurn, 0., 10000000.);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSensitivity, CDialog)
//{{AFX_MSG_MAP(CSensitivity)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN1, OnDeltaposSpin1)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN2, OnDeltaposSpin2)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSensitivity message handlers
void CSensitivity::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
if ( pNMUpDown->iDelta > 0 ) {
m_SensFly /= 1.1 ;
}
else {
m_SensFly *= 1.1 ;
}
UpdateData ( FALSE ) ;
*pResult = 0;
}
void CSensitivity::OnDeltaposSpin2(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
if ( pNMUpDown->iDelta > 0 ) {
m_SensTurn /= 1.1 ;
}
else {
m_SensTurn *= 1.1 ;
}
UpdateData ( FALSE ) ;
*pResult = 0;
}

View File

@@ -1,48 +0,0 @@
#if !defined(AFX_SENSITIVITY_H__F3897393_7D55_11D2_8E5F_0800369C8A03__INCLUDED_)
#define AFX_SENSITIVITY_H__F3897393_7D55_11D2_8E5F_0800369C8A03__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Sensitivity.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CSensitivity dialog
class CSensitivity : public CDialog
{
// Construction
public:
CSensitivity(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CSensitivity)
enum { IDD = IDD_SENS };
double m_SensFly;
double m_SensTurn;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSensitivity)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CSensitivity)
afx_msg void OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDeltaposSpin2(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_SENSITIVITY_H__F3897393_7D55_11D2_8E5F_0800369C8A03__INCLUDED_)

View File

@@ -1,140 +0,0 @@
// Tune.cpp : implementation file
//
#include "stdafx.h"
#include "Tune.h"
#include "AnimationApp.h"
#include "Animationdoc.h"
#include "AnimationView3D.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTune dialog
CTune::CTune(CWnd* pParent /*=NULL*/)
: CDialog(CTune::IDD, pParent)
{
//{{AFX_DATA_INIT(CTune)
m_dAngle = 0.0;
m_dFocus = 0.0;
//}}AFX_DATA_INIT
}
void CTune::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTune)
DDX_Text(pDX, IDC_APPERTURE, m_dAngle);
DDV_MinMaxDouble(pDX, m_dAngle, 5., 179.);
DDX_Text(pDX, IDC_FOCDIST, m_dFocus);
DDV_MinMaxDouble(pDX, m_dFocus, 1.e-003, 10000000.);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTune, CDialog)
//{{AFX_MSG_MAP(CTune)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINANG, OnDeltaposSpinang)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINFOC, OnDeltaposSpinfoc)
ON_EN_CHANGE(IDC_APPERTURE, OnChangeApperture)
ON_EN_CHANGE(IDC_FOCDIST, OnChangeFocdist)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTune message handlers
void CTune::OnDeltaposSpinang(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
if ( pNMUpDown->iDelta > 0 ) {
if ( m_dAngle > 2. )
m_dAngle -= 1. ;
}
else {
if ( m_dAngle < 178. )
m_dAngle += 1 ;
}
UpdateData ( FALSE ) ;
OnChangeApperture() ;
*pResult = 0;
}
void CTune::OnDeltaposSpinfoc(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
if ( pNMUpDown->iDelta > 0 ) {
m_dFocus /= 1.1 ;
}
else {
m_dFocus *= 1.1 ;
}
UpdateData ( FALSE ) ;
OnChangeFocdist() ;
*pResult = 0;
}
void CTune::OnChangeApperture()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function to send the EM_SETEVENTMASK message to the control
// with the ENM_CHANGE flag ORed into the lParam mask.
// TODO: Add your control notification handler code here
( (CAnimationView3D *) m_pView) ->SetFocal ( m_dFocus , m_dAngle ) ;
}
void CTune::OnChangeFocdist()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function to send the EM_SETEVENTMASK message to the control
// with the ENM_CHANGE flag ORed into the lParam mask.
// TODO: Add your control notification handler code here
( (CAnimationView3D *) m_pView) ->SetFocal ( m_dFocus , m_dAngle ) ;
}
BOOL CTune::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
return CDialog::OnCommand(wParam, lParam);
}
BOOL CTune::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
BOOL CTune::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: Add your specialized code here and/or call the base class
return CDialog::OnNotify(wParam, lParam, pResult);
}

View File

@@ -1,54 +0,0 @@
#if !defined(AFX_TUNE_H__D7E45B53_AAD2_11D2_9E97_0800362A0F04__INCLUDED_)
#define AFX_TUNE_H__D7E45B53_AAD2_11D2_9E97_0800362A0F04__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Tune.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CTune dialog
class CTune : public CDialog
{
// Construction
public:
CTune(CWnd* pParent = NULL); // standard constructor
CView * m_pView;
// Dialog Data
//{{AFX_DATA(CTune)
enum { IDD = IDD_TUNE };
double m_dAngle;
double m_dFocus;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTune)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CTune)
afx_msg void OnDeltaposSpinang(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDeltaposSpinfoc(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnChangeApperture();
afx_msg void OnChangeFocdist();
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_TUNE_H__D7E45B53_AAD2_11D2_9E97_0800362A0F04__INCLUDED_)

View File

@@ -3,6 +3,7 @@
#include "Sample2D_Image.h"
#include <Graphic3d_Texture2Dmanual.hxx>
#include <Image_AlienPixMap.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Sample2D_Image,AIS_Shape)
@@ -19,10 +20,13 @@ Sample2D_Image::Sample2D_Image(TCollection_AsciiString& aFileName,
}
void Sample2D_Image::MakeShape()
{
Handle(Graphic3d_Texture1D) anImageTexture =
new Graphic3d_Texture1Dsegment(myFilename);
Standard_Real coeff = (Standard_Real)(anImageTexture->GetImage()->Height())/
(anImageTexture->GetImage()->Width())*myScale;
Standard_Real coeff = 1.0;
Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
if (anImage->Load (myFilename))
{
coeff = Standard_Real(anImage->Height()) / Standard_Real(anImage->Width()) * myScale;
}
TopoDS_Edge E1 = BRepBuilderAPI_MakeEdge(gp_Pnt(myX,myY,0.), gp_Pnt(100*myScale+myX,myY,0.));
TopoDS_Edge E2 = BRepBuilderAPI_MakeEdge(gp_Pnt(100*myScale+myX,myY,0.), gp_Pnt(100*myScale+myX,100*coeff+myY,0.));
TopoDS_Edge E3 = BRepBuilderAPI_MakeEdge(gp_Pnt(100*myScale+myX,100*coeff+myY,0.), gp_Pnt(myX,100*coeff+myY,0.));

View File

@@ -1755,6 +1755,133 @@ gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& t
return theCtx ->GravityPoint (theView);
}
// =======================================================================
// function : handleNavigationKeys
// purpose :
// =======================================================================
AIS_WalkDelta AIS_ViewController::handleNavigationKeys (const Handle(AIS_InteractiveContext)& ,
const Handle(V3d_View)& theView)
{
// navigation keys
double aCrouchRatio = 1.0, aRunRatio = 1.0;
if (myNavigationMode == AIS_NavigationMode_FirstPersonFlight)
{
aRunRatio = 3.0;
}
const double aRotSpeed = 0.5;
const double aWalkSpeedCoef = WalkSpeedRelative();
AIS_WalkDelta aWalk = FetchNavigationKeys (aCrouchRatio, aRunRatio);
if (aWalk.IsJumping())
{
// ask more frames
setAskNextFrame();
theView->Invalidate();
}
if (aWalk.IsEmpty())
{
return aWalk;
}
else if (myGL.OrbitRotation.ToRotate
|| myGL.OrbitRotation.ToStart)
{
return aWalk;
}
gp_XYZ aMin, aMax;
const Bnd_Box aBndBox = theView->View()->MinMaxValues();
if (!aBndBox.IsVoid())
{
aMin = aBndBox.CornerMin().XYZ();
aMax = aBndBox.CornerMax().XYZ();
}
double aBndDiam = Max (Max (aMax.X() - aMin.X(), aMax.Y() - aMin.Y()), aMax.Z() - aMin.Z());
if (aBndDiam <= gp::Resolution())
{
aBndDiam = 0.001;
}
const double aWalkSpeed = myNavigationMode != AIS_NavigationMode_Orbit
&& myNavigationMode != AIS_NavigationMode_FirstPersonFlight
? theView->View()->UnitFactor() * WalkSpeedAbsolute()
: aWalkSpeedCoef * aBndDiam;
const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
? theView->View()->BaseXRCamera()
: theView->Camera();
// move forward in plane XY and up along Z
const gp_Dir anUp = ToLockOrbitZUp() ? gp::DZ() : aCam->OrthogonalizedUp();
if (aWalk.ToMove()
&& myToAllowPanning)
{
const gp_Vec aSide = -aCam->SideRight();
gp_XYZ aFwd = aCam->Direction().XYZ();
aFwd -= anUp.XYZ() * (anUp.XYZ() * aFwd);
gp_XYZ aMoveVec;
if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
{
if (!aCam->IsOrthographic())
{
aMoveVec += aFwd * aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeed;
}
}
if (!aWalk[AIS_WalkTranslation_Side].IsEmpty())
{
aMoveVec += aSide.XYZ() * aWalk[AIS_WalkTranslation_Side].Value * aWalk[AIS_WalkTranslation_Side].Pressure * aWalkSpeed;
}
if (!aWalk[AIS_WalkTranslation_Up].IsEmpty())
{
aMoveVec += anUp.XYZ() * aWalk[AIS_WalkTranslation_Up].Value * aWalk[AIS_WalkTranslation_Up].Pressure * aWalkSpeed;
}
{
if (aCam->IsOrthographic())
{
if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
{
const double aZoomDelta = aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeedCoef;
handleZoom (theView, Aspect_ScrollDelta (aZoomDelta * 100.0), NULL);
}
}
gp_Trsf aTrsfTranslate;
aTrsfTranslate.SetTranslation (aMoveVec);
aCam->Transform (aTrsfTranslate);
}
}
if (myNavigationMode == AIS_NavigationMode_Orbit
&& myToAllowRotation)
{
if (!aWalk[AIS_WalkRotation_Yaw].IsEmpty())
{
gp_Trsf aTrsfRot;
aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), anUp), aWalk[AIS_WalkRotation_Yaw].Value * aRotSpeed);
aCam->Transform (aTrsfRot);
}
if (!aWalk[AIS_WalkRotation_Pitch].IsEmpty())
{
const gp_Vec aSide = -aCam->SideRight();
gp_Trsf aTrsfRot;
aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), aSide), -aWalk[AIS_WalkRotation_Pitch].Value * aRotSpeed);
aCam->Transform (aTrsfRot);
}
if (!aWalk[AIS_WalkRotation_Roll].IsEmpty()
&& !ToLockOrbitZUp())
{
gp_Trsf aTrsfRot;
aTrsfRot.SetRotation (gp_Ax1 (aCam->Center(), aCam->Direction()), aWalk[AIS_WalkRotation_Roll].Value * aRotSpeed);
aCam->Transform (aTrsfRot);
}
}
// ask more frames
setAskNextFrame();
theView->Invalidate();
theView->View()->SynchronizeXRBaseToPosedCamera();
return aWalk;
}
// =======================================================================
// function : handleCameraActions
// purpose :
@@ -2929,17 +3056,17 @@ void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)&
{
const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
handleXRInput (theCtx, theView, aWalk);
if (theView->View()->IsActiveXR())
{
theView->View()->SetupXRPosedCamera();
}
handleMoveTo (theCtx, theView);
handleCameraActions (theCtx, theView, aWalk);
theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
handleXRPresentations (theCtx, theView);
handleMoveTo (theCtx, theView);
handleViewRedraw (theCtx, theView);
theView->View()->UnsetXRPosedCamera();

View File

@@ -490,6 +490,11 @@ public:
public:
//! Perform navigation.
//! This method is expected to be called from rendering thread.
Standard_EXPORT virtual AIS_WalkDelta handleNavigationKeys (const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView);
//! Perform camera actions.
//! This method is expected to be called from rendering thread.
Standard_EXPORT virtual void handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,

View File

@@ -43,7 +43,10 @@ public:
}
//! Image reader.
virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE { return myImageSource->ReadImage(); }
virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE
{
return myImageSource->ReadImage (theSupported);
}
protected:
Handle(Image_Texture) myImageSource;

View File

@@ -261,7 +261,7 @@ public:
protected:
//! Read image.
virtual Handle(Image_PixMap) ReadImage() const Standard_OVERRIDE
virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& ) const Standard_OVERRIDE
{
Handle(VRImagePixmap) aPixmap = new VRImagePixmap();
if (!aPixmap->Load (myVrTextureId, myVrModelName))

View File

@@ -1174,13 +1174,9 @@ void BRep_Builder::Transfert(const TopoDS_Edge& Ein,
const TopoDS_Edge& Eout) const
{
const Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*) &Ein.TShape());
if(TE->Locked())
{
throw TopoDS_LockedShape("BRep_Builder::Transfert");
}
const Standard_Real tol = TE->Tolerance();
BRep_ListOfCurveRepresentation& lcr = TE->ChangeCurves();
const BRep_ListOfCurveRepresentation& lcr = TE->Curves();
BRep_ListIteratorOfListOfCurveRepresentation itcr(lcr);
while (itcr.More()) {

View File

@@ -149,7 +149,7 @@ void BRepExtrema_DistShapeShape::DistanceMapMap (const TopTools_IndexedMapOfShap
const TopoDS_Shape& aShape1 = theMap1 (aPair.Index1);
const TopoDS_Shape& aShape2 = theMap2 (aPair.Index2);
BRepExtrema_DistanceSS aDistTool (aShape1, aShape2, aBox1, aBox2, myDistRef, myEps, myFlag);
BRepExtrema_DistanceSS aDistTool (aShape1, aShape2, aBox1, aBox2, myDistRef, myEps);
if (aDistTool.IsDone())
{
if (aDistTool.DistValue() < myDistRef - myEps)
@@ -194,7 +194,8 @@ BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape()
myEps (Precision::Confusion()),
myIsInitS1 (Standard_False),
myIsInitS2 (Standard_False),
myFlag (Extrema_ExtFlag_MINMAX)
myFlag (Extrema_ExtFlag_MINMAX),
myAlgo (Extrema_ExtAlgo_Grad)
{
//
}
@@ -205,14 +206,16 @@ BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape()
//=======================================================================
BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,
const TopoDS_Shape& Shape2,
const Extrema_ExtFlag F)
const Extrema_ExtFlag F,
const Extrema_ExtAlgo A)
: myDistRef (0.0),
myIsDone (Standard_False),
myInnerSol (Standard_False),
myEps (Precision::Confusion()),
myIsInitS1 (Standard_False),
myIsInitS2 (Standard_False),
myFlag (F)
myFlag (F),
myAlgo (A)
{
LoadS1(Shape1);
LoadS2(Shape2);
@@ -227,14 +230,16 @@ BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape
BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,
const TopoDS_Shape& Shape2,
const Standard_Real theDeflection,
const Extrema_ExtFlag F)
const Extrema_ExtFlag F,
const Extrema_ExtAlgo A)
: myDistRef (0.0),
myIsDone (Standard_False),
myInnerSol (Standard_False),
myEps (theDeflection),
myIsInitS1 (Standard_False),
myIsInitS2 (Standard_False),
myFlag (F)
myFlag (F),
myAlgo (A)
{
LoadS1(Shape1);
LoadS2(Shape2);

View File

@@ -18,6 +18,7 @@
#include <BRepExtrema_SeqOfSolution.hxx>
#include <BRepExtrema_SolutionElem.hxx>
#include <BRepExtrema_SupportType.hxx>
#include <Extrema_ExtAlgo.hxx>
#include <Extrema_ExtFlag.hxx>
#include <gp_Pnt.hxx>
#include <TopoDS_Shape.hxx>
@@ -38,9 +39,9 @@ class BRepExtrema_DistShapeShape
Standard_EXPORT BRepExtrema_DistShapeShape();
//! computation of the minimum distance (value and pair of points) using default deflection <br>
//! Default value is Precision::Confusion(). <br>
Standard_EXPORT BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,const TopoDS_Shape& Shape2,const Extrema_ExtFlag F = Extrema_ExtFlag_MIN);
Standard_EXPORT BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,const TopoDS_Shape& Shape2,const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX,const Extrema_ExtAlgo A = Extrema_ExtAlgo_Grad);
//! create tool and load both shapes into it <br>
Standard_EXPORT BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,const TopoDS_Shape& Shape2,const Standard_Real theDeflection,const Extrema_ExtFlag F = Extrema_ExtFlag_MIN);
Standard_EXPORT BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,const TopoDS_Shape& Shape2,const Standard_Real theDeflection,const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX,const Extrema_ExtAlgo A = Extrema_ExtAlgo_Grad);
void SetDeflection(const Standard_Real theDeflection)
{
@@ -128,6 +129,11 @@ class BRepExtrema_DistShapeShape
myFlag = F;
}
void SetAlgo(const Extrema_ExtAlgo A)
{
myAlgo = A;
}
private:
//! computes the minimum distance between two maps of shapes (Face,Edge,Vertex) <br>
@@ -150,6 +156,7 @@ private:
Standard_Boolean myIsInitS1;
Standard_Boolean myIsInitS2;
Extrema_ExtFlag myFlag;
Extrema_ExtAlgo myAlgo;
Bnd_SeqOfBox myBV1;
Bnd_SeqOfBox myBV2;
Bnd_SeqOfBox myBE1;

View File

@@ -772,7 +772,7 @@ void BRepExtrema_DistanceSS::Perform(const TopoDS_Vertex& S1, const TopoDS_Face&
const Standard_Real Dst=B1.Distance(B2);
if ((Dst < myDstRef - myEps) || (fabs(Dst-myDstRef) < myEps))
{
BRepExtrema_ExtPF Ext(S1,S2,myFlag);
BRepExtrema_ExtPF Ext(S1,S2,myFlag,myAlgo);
const Standard_Integer NbExtrema = Ext.IsDone()? Ext.NbExt() : 0;
if ( NbExtrema > 0 )
{
@@ -828,7 +828,7 @@ void BRepExtrema_DistanceSS::Perform(const TopoDS_Face& S1, const TopoDS_Vertex&
const Standard_Real Dst=B1.Distance(B2);
if ((Dst < myDstRef - myEps) || (fabs(Dst-myDstRef) < myEps))
{
BRepExtrema_ExtPF Ext(S2,S1,myFlag);
BRepExtrema_ExtPF Ext(S2,S1,myFlag,myAlgo);
const Standard_Integer NbExtrema = Ext.IsDone()? Ext.NbExt() : 0;
if ( NbExtrema > 0 )
{

View File

@@ -16,6 +16,7 @@
#include <BRepExtrema_SeqOfSolution.hxx>
#include <Extrema_ExtFlag.hxx>
#include <Extrema_ExtAlgo.hxx>
#include <Precision.hxx>
#include <Standard_DefineAlloc.hxx>
@@ -38,8 +39,9 @@ class BRepExtrema_DistanceSS
BRepExtrema_DistanceSS(const TopoDS_Shape& S1, const TopoDS_Shape& S2,
const Bnd_Box& B1, const Bnd_Box& B2,
const Standard_Real DstRef,
const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX)
: myDstRef(DstRef), myModif(Standard_False), myEps(Precision::Confusion()), myFlag(F)
const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX,
const Extrema_ExtAlgo A = Extrema_ExtAlgo_Grad)
: myDstRef(DstRef), myModif(Standard_False), myEps(Precision::Confusion()), myFlag(F), myAlgo(A)
{
Perform(S1, S2, B1, B2);
}
@@ -50,8 +52,9 @@ class BRepExtrema_DistanceSS
BRepExtrema_DistanceSS(const TopoDS_Shape& S1, const TopoDS_Shape& S2,
const Bnd_Box& B1, const Bnd_Box& B2,
const Standard_Real DstRef, const Standard_Real aDeflection,
const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX)
: myDstRef(DstRef), myModif(Standard_False), myEps(aDeflection), myFlag(F)
const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX,
const Extrema_ExtAlgo A = Extrema_ExtAlgo_Grad)
: myDstRef(DstRef), myModif(Standard_False), myEps(aDeflection), myFlag(F), myAlgo(A)
{
Perform(S1, S2, B1, B2);
}
@@ -80,6 +83,11 @@ class BRepExtrema_DistanceSS
{
myFlag = F;
}
//! sets the flag controlling ...
void SetAlgo(const Extrema_ExtAlgo A)
{
myAlgo = A;
}
private:
@@ -122,6 +130,7 @@ class BRepExtrema_DistanceSS
Standard_Boolean myModif;
Standard_Real myEps;
Extrema_ExtFlag myFlag;
Extrema_ExtAlgo myAlgo;
};
#endif

View File

@@ -32,9 +32,9 @@
//=======================================================================
BRepExtrema_ExtPF::BRepExtrema_ExtPF(const TopoDS_Vertex& TheVertex, const TopoDS_Face& TheFace,
const Extrema_ExtFlag TheFlag)
const Extrema_ExtFlag TheFlag, const Extrema_ExtAlgo TheAlgo)
{
Initialize(TheFace,TheFlag);
Initialize(TheFace,TheFlag,TheAlgo);
Perform(TheVertex,TheFace);
}
@@ -44,7 +44,7 @@ BRepExtrema_ExtPF::BRepExtrema_ExtPF(const TopoDS_Vertex& TheVertex, const TopoD
//=======================================================================
void BRepExtrema_ExtPF::Initialize(const TopoDS_Face& TheFace,
const Extrema_ExtFlag TheFlag)
const Extrema_ExtFlag TheFlag, const Extrema_ExtAlgo TheAlgo)
{
// cette surface doit etre en champ. Extrema ne fait
// pas de copie et prend seulement un pointeur dessus.
@@ -60,6 +60,7 @@ void BRepExtrema_ExtPF::Initialize(const TopoDS_Face& TheFace,
Standard_Real U1, U2, V1, V2;
BRepTools::UVBounds(TheFace, U1, U2, V1, V2);
myExtPS.SetFlag(TheFlag);
myExtPS.SetAlgo(TheAlgo);
myExtPS.Initialize(mySurf, U1, U2, V1, V2, aTolU, aTolV);
}

View File

@@ -21,6 +21,7 @@
#include <Extrema_SequenceOfPOnSurf.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <Extrema_ExtFlag.hxx>
#include <Extrema_ExtAlgo.hxx>
class TopoDS_Vertex;
class TopoDS_Face;
@@ -37,10 +38,12 @@ class BRepExtrema_ExtPF
{}
//! It calculates all the distances. <br>
Standard_EXPORT BRepExtrema_ExtPF(const TopoDS_Vertex& TheVertex,const TopoDS_Face& TheFace,
const Extrema_ExtFlag TheFlag = Extrema_ExtFlag_MINMAX);
const Extrema_ExtFlag TheFlag = Extrema_ExtFlag_MINMAX,
const Extrema_ExtAlgo TheAlgo = Extrema_ExtAlgo_Grad);
Standard_EXPORT void Initialize(const TopoDS_Face& TheFace,
const Extrema_ExtFlag TheFlag = Extrema_ExtFlag_MINMAX);
const Extrema_ExtFlag TheFlag = Extrema_ExtFlag_MINMAX,
const Extrema_ExtAlgo TheAlgo = Extrema_ExtAlgo_Grad);
//! An exception is raised if the fields have not been initialized. <br>
//! Be careful: this method uses the Face only for classify not for the fields. <br>
@@ -76,6 +79,11 @@ class BRepExtrema_ExtPF
myExtPS.SetFlag(F);
}
void SetAlgo(const Extrema_ExtAlgo A)
{
myExtPS.SetAlgo(A);
}
private:
Extrema_ExtPS myExtPS;

View File

@@ -721,6 +721,7 @@ void BRepFill_Filling::Build()
gp_Pnt aPnt = BRep_Tool::Pnt(V1);
NewV1 = BRepLib_MakeVertex(aPnt);
BB.UpdateVertex(NewV1, dmax);
myOldNewMap.Bind(V1.Oriented(TopAbs_FORWARD), NewV1);
}
if (myOldNewMap.IsBound(V2))
@@ -730,6 +731,7 @@ void BRepFill_Filling::Build()
gp_Pnt aPnt = BRep_Tool::Pnt(V2);
NewV2 = BRepLib_MakeVertex(aPnt);
BB.UpdateVertex(NewV2, dmax);
myOldNewMap.Bind(V2.Oriented(TopAbs_FORWARD), NewV2);
}
NewV1.Orientation(TopAbs_FORWARD);
@@ -742,9 +744,6 @@ void BRepFill_Filling::Build()
BRepLib::SameParameter(NewEdge, dmax, Standard_True);
FinalEdges.Append(NewEdge);
myOldNewMap.Bind(InitEdge.Oriented(TopAbs_FORWARD), NewEdge.Oriented(TopAbs_FORWARD));
myOldNewMap.Bind(V1.Oriented(TopAbs_FORWARD), NewV1.Oriented(TopAbs_FORWARD));
if (!V1.IsSame(V2))
myOldNewMap.Bind(V2.Oriented(TopAbs_FORWARD), NewV2.Oriented(TopAbs_FORWARD));
}
TopoDS_Wire FinalWire = WireFromList(FinalEdges);

View File

@@ -23,7 +23,6 @@
#include <BRepLib_MakeFace.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <GCPnts.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
@@ -179,6 +178,39 @@ BRepLib_FindSurface::BRepLib_FindSurface(const TopoDS_Shape& S,
namespace
{
static void fillParams (const TColStd_Array1OfReal& theKnots,
Standard_Integer theDegree,
Standard_Real theParMin,
Standard_Real theParMax,
NCollection_Vector<Standard_Real>& theParams)
{
Standard_Real aPrevPar = theParMin;
theParams.Append (aPrevPar);
Standard_Integer aNbP = Max (theDegree, 1);
for (Standard_Integer i = 1;
(i < theKnots.Length()) && (theKnots (i) < (theParMax - Precision::PConfusion())); ++i)
{
if (theKnots (i + 1) < theParMin + Precision::PConfusion())
continue;
Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / aNbP;
for (Standard_Integer k = 1; k <= aNbP ; ++k)
{
Standard_Real aPar = theKnots (i) + k * aStep;
if (aPar > theParMax - Precision::PConfusion())
break;
if (aPar > aPrevPar + Precision::PConfusion())
{
theParams.Append (aPar);
aPrevPar = aPar;
}
}
}
theParams.Append (theParMax);
}
static void fillPoints (const BRepAdaptor_Curve& theCurve,
const NCollection_Vector<Standard_Real> theParams,
@@ -326,13 +358,13 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape& S,
aKnots.SetValue (1, GC->FirstParameter());
aKnots.SetValue (2, GC->LastParameter());
GCPnts::FillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams);
fillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams);
break;
}
case GeomAbs_BSplineCurve:
{
Handle(Geom_BSplineCurve) GC = c.BSpline();
GCPnts::FillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams);
fillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams);
break;
}
case GeomAbs_Line:
@@ -359,7 +391,7 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape& S,
aBounds.SetValue (1, dfUf);
aBounds.SetValue (2, dfUl);
GCPnts::FillParams (aBounds, iNbPoints - 1, dfUf, dfUl, aParams);
fillParams (aBounds, iNbPoints - 1, dfUf, dfUl, aParams);
}
}

View File

@@ -165,7 +165,7 @@ private:
const TopTools_IndexedMapOfShape& myMapOfShape; //vertices
gp_Pnt myP;
Standard_Real mySTol;
Standard_Real myTolP;
Standard_Integer myVInd;
Bnd_Box myVBox;
NCollection_List<Standard_Integer> myResultInd;

View File

@@ -155,8 +155,10 @@ Standard_Boolean BRepLib_MakeWire::BRepLib_BndBoxVertexSelector::
Standard_Real aTolV = BRep_Tool::Tolerance(aV);
Standard_Real aL = myP.SquareDistance(aVPnt);
Standard_Real aSTol = aTolV + myTolP;
aSTol *= aSTol;
if (aL < Max(aTolV*aTolV, mySTol))
if (aL <= aSTol)
{
myResultInd.Append(theObj);
return Standard_True;
@@ -176,7 +178,7 @@ void BRepLib_MakeWire::BRepLib_BndBoxVertexSelector::
myP = theP;
myVBox.Add(myP);
myVBox.Enlarge(theTol);
mySTol = theTol*theTol;
myTolP = theTol;
myVInd = theVInd;
}

View File

@@ -77,7 +77,7 @@ static Standard_Integer distmini(Draw_Interpretor& di, Standard_Integer n, const
if (n == 5)
aDeflection = Draw::Atof(a[4]);
BRepExtrema_DistShapeShape dst(S1 ,S2, aDeflection, Extrema_ExtFlag_MIN);
BRepExtrema_DistShapeShape dst(S1 ,S2, aDeflection);
if (dst.IsDone())
{

View File

@@ -617,9 +617,9 @@ static Standard_Integer getedgeregul
//=======================================================================
static Standard_Integer projponf(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 3 || n > 4) {
if (n < 3 || n > 5) {
di << "Project point on the face.\n";
di << "Usage: projponf face pnt [extrema flag: -min/-max/-minmax]\n";
di << "Usage: projponf face pnt [extrema flag: -min/-max/-minmax] [extrema algo: -g(grad)/-t(tree)]\n";
return 1;
}
// get face
@@ -642,6 +642,7 @@ static Standard_Integer projponf(Draw_Interpretor& di, Standard_Integer n, const
//
// get projection options
// default values;
Extrema_ExtAlgo anExtAlgo = Extrema_ExtAlgo_Grad;
Extrema_ExtFlag anExtFlag = Extrema_ExtFlag_MINMAX;
//
for (Standard_Integer i = 3; i < n; ++i) {
@@ -654,6 +655,12 @@ static Standard_Integer projponf(Draw_Interpretor& di, Standard_Integer n, const
else if (!strcasecmp(a[i], "-minmax")) {
anExtFlag = Extrema_ExtFlag_MINMAX;
}
else if (!strcasecmp(a[i], "-t")) {
anExtAlgo = Extrema_ExtAlgo_Tree;
}
else if (!strcasecmp(a[i], "-g")) {
anExtAlgo = Extrema_ExtAlgo_Grad;
}
}
//
// get surface
@@ -670,6 +677,7 @@ static Standard_Integer projponf(Draw_Interpretor& di, Standard_Integer n, const
GeomAPI_ProjectPointOnSurf aProjPS;
aProjPS.Init(aSurf, aUMin, aUMax, aVMin, aVMax);
// set the options
aProjPS.SetExtremaAlgo(anExtAlgo);
aProjPS.SetExtremaFlag(anExtFlag);
// perform projection
aProjPS.Perform(aP);
@@ -758,7 +766,7 @@ void BRepTest::SurfaceCommands(Draw_Interpretor& theCommands)
theCommands.Add ("getedgeregularity", "getedgeregularity edge face1 [face2]", __FILE__,getedgeregul,g);
theCommands.Add ("projponf",
"projponf face pnt [extrema flag: -min/-max/-minmax]\n"
"projponf face pnt [extrema flag: -min/-max/-minmax] [extrema algo: -g(grad)/-t(tree)]\n"
"\t\tProject point on the face.",
__FILE__, projponf, g);
}

View File

@@ -1156,3 +1156,112 @@ TopAbs_Orientation BRepTools::OriEdgeInFace (const TopoDS_Edge& E,
}
throw Standard_ConstructionError("BRepTools::OriEdgeInFace");
}
namespace
{
//=======================================================================
//function : findInternalsToKeep
//purpose : Looks for internal sub-shapes which has to be kept to preserve
// topological connectivity.
//=======================================================================
static void findInternalsToKeep (const TopoDS_Shape& theS,
TopTools_MapOfShape& theAllNonInternals,
TopTools_MapOfShape& theAllInternals,
TopTools_MapOfShape& theShapesToKeep)
{
for (TopoDS_Iterator it (theS, Standard_True); it.More(); it.Next())
{
const TopoDS_Shape& aSS = it.Value();
findInternalsToKeep (aSS, theAllNonInternals, theAllInternals, theShapesToKeep);
if (aSS.Orientation() == TopAbs_INTERNAL)
theAllInternals.Add (aSS);
else
theAllNonInternals.Add (aSS);
if (theAllNonInternals.Contains(aSS) && theAllInternals.Contains (aSS))
theShapesToKeep.Add (aSS);
}
}
//=======================================================================
//function : removeShapes
//purpose : Removes sub-shapes from the shape
//=======================================================================
static void removeShapes (TopoDS_Shape& theS,
const TopTools_ListOfShape& theLS)
{
BRep_Builder aBB;
Standard_Boolean isFree = theS.Free();
theS.Free (Standard_True);
for (TopTools_ListOfShape::Iterator it (theLS); it.More(); it.Next())
{
aBB.Remove (theS, it.Value());
}
theS.Free (isFree);
}
//=======================================================================
//function : removeInternals
//purpose : Removes recursively all internal sub-shapes from the given shape.
// Returns true if all sub-shapes have been removed from the shape.
//=======================================================================
static Standard_Boolean removeInternals (TopoDS_Shape& theS,
const TopTools_MapOfShape* theShapesToKeep)
{
TopTools_ListOfShape aLRemove;
for (TopoDS_Iterator it (theS, Standard_True); it.More(); it.Next())
{
const TopoDS_Shape& aSS = it.Value();
if (aSS.Orientation() == TopAbs_INTERNAL)
{
if (!theShapesToKeep || !theShapesToKeep->Contains (aSS))
aLRemove.Append (aSS);
}
else
{
if (removeInternals (*(TopoDS_Shape*)&aSS, theShapesToKeep))
aLRemove.Append (aSS);
}
}
Standard_Integer aNbSToRemove = aLRemove.Extent();
if (aNbSToRemove)
{
removeShapes (theS, aLRemove);
return (theS.NbChildren() == 0);
}
return Standard_False;
}
}
//=======================================================================
//function : RemoveInternals
//purpose :
//=======================================================================
void BRepTools::RemoveInternals (TopoDS_Shape& theS,
const Standard_Boolean theForce)
{
TopTools_MapOfShape *pMKeep = NULL, aMKeep;
if (!theForce)
{
// Find all internal sub-shapes which has to be kept to preserve topological connectivity.
// Note that if the multi-connected shape is not directly contained in some shape,
// but as a part of bigger sub-shape which will be removed, the multi-connected
// shape is going to be removed also, breaking topological connectivity.
// For instance, <theS> is a compound of the face and edge, which does not
// belong to the face. The face contains internal wire and the edge shares
// the vertex with one of the vertices of that wire. The vertex is not directly
// contained in the face, thus will be removed as part of internal wire, and topological
// connectivity between edge and face will be lost.
TopTools_MapOfShape anAllNonInternals, anAllInternals;
findInternalsToKeep (theS, anAllNonInternals, anAllInternals, aMKeep);
if (aMKeep.Extent())
pMKeep = &aMKeep;
}
removeInternals (theS, pMKeep);
}

View File

@@ -238,6 +238,16 @@ public:
Standard_EXPORT static TopAbs_Orientation OriEdgeInFace(const TopoDS_Edge& theEdge,
const TopoDS_Face& theFace);
//! Removes internal sub-shapes from the shape.
//! The check on internal status is based on orientation of sub-shapes,
//! classification is not performed.
//! Before removal of internal sub-shapes the algorithm checks if such
//! removal is not going to break topological connectivity between sub-shapes.
//! The flag <theForce> if set to true disables the connectivity check and clears
//! the given shape from all sub-shapes with internal orientation.
Standard_EXPORT static void RemoveInternals (TopoDS_Shape& theS,
const Standard_Boolean theForce = Standard_False);
protected:

View File

@@ -66,18 +66,6 @@ public: //! @name Adding elements in BVH
BVH_Object<NumType, Dimension>::myIsDirty = Standard_True;
}
//! Allows to update the box of the element while the tree is not yet built
virtual void UpdateBox (const Standard_Integer theId, const BVH_Box<NumType, Dimension>& theNewBox)
{
if (BVH_Object<NumType, Dimension>::myIsDirty)
{
if (theId >= 0 && theId < Size())
{
myBoxes[theId] = theNewBox;
}
}
}
public: //! @name BVH construction
//! BVH construction

View File

@@ -84,7 +84,7 @@ public: //! @name Necessary overrides for BVH construction
//! Returns the bounding box with the given index.
virtual BVH_Box <NumType, Dimension> Box (const Standard_Integer theIndex) const Standard_OVERRIDE
{
return this->myBoxes[myIndices[theIndex]];
return myBoxes[myIndices[theIndex]];
}
//! Swaps indices of two specified boxes.
@@ -97,7 +97,7 @@ public: //! @name Necessary overrides for BVH construction
//! Returns the Element with the index theIndex.
virtual DataType Element (const Standard_Integer theIndex) const
{
return this->myElements[myIndices[theIndex]];
return myElements[myIndices[theIndex]];
}
protected: //! @name Fields

View File

@@ -88,24 +88,6 @@ public: //! @name Point-Box Square distance
return aDist;
}
//! Computes Max square distance between point and bounding box
static T PointBoxMaxSquareDistance (const BVH_VecNt& thePoint,
const BVH_VecNt& theCMin,
const BVH_VecNt& theCMax)
{
T aDist = 0;
for (int i = 0; i < N; ++i)
{
T dmin = 0, dmax = 0;
if (thePoint[i] > theCMin[i]) { dmin = thePoint[i] - theCMin[i]; }
if (thePoint[i] < theCMax[i]) { dmax = theCMax[i] - thePoint[i]; }
T d = dmin > dmax ? dmin : dmax;
d *= d;
aDist += d;
}
return aDist;
}
public: //! @name Point-Box projection
//! Computes projection of point on bounding box
@@ -128,6 +110,7 @@ public: //! @name Point-Box projection
{
return thePoint.cwiseMax (theCMin).cwiseMin (theCMax);
}
public: //! @name Point-Triangle Square distance
//! Computes square distance between point and triangle

View File

@@ -1416,6 +1416,39 @@ static Standard_Integer binrestore(Draw_Interpretor& di, Standard_Integer n, con
return 0;
}
//=======================================================================
// removeinternals
//=======================================================================
static Standard_Integer removeInternals (Draw_Interpretor& di,
Standard_Integer n,
const char** a)
{
if (n < 2)
{
di.PrintHelp (a[0]);
return 1;
}
TopoDS_Shape aShape = DBRep::Get (a[1]);
if (aShape.IsNull())
{
di << a[1] << "is a null shape\n";
return 1;
}
Standard_Boolean isForce = Standard_False;
if (n > 2)
{
isForce = (Draw::Atoi (a[2]) != 0);
}
BRepTools::RemoveInternals (aShape, isForce);
DBRep::Set (a[1], aShape);
return 0;
}
//=======================================================================
//function : BasicCommands
//purpose :
@@ -1487,6 +1520,12 @@ void DBRep::BasicCommands(Draw_Interpretor& theCommands)
theCommands.Add("binrestore", "binrestore filename shape\n"
"\t\trestore the shape from the binary format file",
__FILE__, binrestore, g);
theCommands.Add ("removeinternals", "removeinternals shape [force flag {0/1}]"
"\n\t\t Removes sub-shapes with internal orientation from the shape.\n"
"\n\t\t Force flag disables the check on topological connectivity and"
"removes all internal sub-shapes\n",
__FILE__, removeInternals, g);
}
//=======================================================================

View File

@@ -18,10 +18,6 @@
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <Bnd_OBB.hxx>
#include <Bnd_Box.hxx>
#include <Draw_Box.hxx>
// This file defines global functions not declared in any public header,
// intended for use from debugger prompt (Command Window in Visual Studio)
@@ -44,47 +40,3 @@ Standard_EXPORT const char* Draw_Eval (const char *theCommandStr)
return anException.GetMessageString();
}
}
//=======================================================================
//function : DBRep_SetOBB
//purpose : Draw OBB
//=======================================================================
Standard_EXPORT const char* Draw_SetOBB(const char* theNameStr, void* theBox)
{
if (theNameStr == 0 || theBox == 0)
{
return "Error: name or box is null";
}
try {
Bnd_OBB B = *(Bnd_OBB*)theBox;
Handle(Draw_Box) DB = new Draw_Box (B, Draw_orange);
Draw::Set (theNameStr, DB);
return theNameStr;
}
catch (Standard_Failure const& anException)
{
return anException.GetMessageString();
}
}
//=======================================================================
//function : DBRep_SetBox
//purpose : Draw Box
//=======================================================================
Standard_EXPORT const char* Draw_SetBox(const char* theNameStr, void* theBox)
{
if (theNameStr == 0 || theBox == 0)
{
return "Error: name or box is null";
}
try {
Bnd_Box B = *(Bnd_Box*)theBox;
Handle(Draw_Box) DB = new Draw_Box (B, Draw_orange);
Draw::Set (theNameStr, DB);
return theNameStr;
}
catch (Standard_Failure const& anException)
{
return anException.GetMessageString();
}
}

View File

@@ -102,8 +102,8 @@ Standard_Boolean Draw_ProgressIndicator::Show(const Standard_Boolean force)
if ( scale.GetName().IsNull() ) continue; // skip unnamed scopes
aText << " " << scale.GetName()->ToCString() << ": ";
// if scope has subscopes, print end of subscope as its current position
Standard_Real locPos = ( i >1 ? GetScope ( i-1 ).GetLast() : GetPosition() );
// if scope has subscopes, print end of subscope as it s current position
Standard_Real locPos = ( (i >1 && GetPosition()!=0) ? GetScope ( i-1 ).GetLast() : GetPosition() );
// print progress info differently for finite and infinite scopes
if ( scale.GetInfinite() )
{

View File

@@ -1,4 +1,7 @@
// Copyright (c) 2014 OPEN CASCADE SAS
// Created on: 1991-02-26
// Created by: Isabelle GRIGNON
// Copyright (c) 1991-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
@@ -11,6 +14,14 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <OcctJni_Window.hxx>
#ifndef _Extrema_ExtAlgo_HeaderFile
#define _Extrema_ExtAlgo_HeaderFile
IMPLEMENT_STANDARD_RTTIEXT(OcctJni_Window, Aspect_Window)
enum Extrema_ExtAlgo
{
Extrema_ExtAlgo_Grad,
Extrema_ExtAlgo_Tree
};
#endif // _Extrema_ExtAlgo_HeaderFile

View File

@@ -17,16 +17,12 @@
#ifndef _Extrema_ExtFlag_HeaderFile
#define _Extrema_ExtFlag_HeaderFile
//! Enumeration describes the objective for extrema algorithms.
//! Generally:
//! - *Extrema_ExtFlag_MIN* - means that only minimal solutions are required
//! - *Extrema_ExtFlag_MAX* - means that only maximal solutions are required
//! - *Extrema_ExtFlag_MINMAX* - means that all solutions are required
enum Extrema_ExtFlag
{
Extrema_ExtFlag_MIN,
Extrema_ExtFlag_MAX,
Extrema_ExtFlag_MINMAX
Extrema_ExtFlag_MIN,
Extrema_ExtFlag_MAX,
Extrema_ExtFlag_MINMAX
};
#endif // _Extrema_ExtFlag_HeaderFile

View File

@@ -144,7 +144,7 @@ void Extrema_ExtPExtS::MakePreciser (Standard_Real& U,
}
//=============================================================================
Extrema_ExtPExtS::Extrema_ExtPExtS (const Handle (Extrema_GenExtPS)& theExtPS)
Extrema_ExtPExtS::Extrema_ExtPExtS()
: myuinf(0.0),
myusup(0.0),
mytolu(0.0),
@@ -153,8 +153,7 @@ Extrema_ExtPExtS::Extrema_ExtPExtS (const Handle (Extrema_GenExtPS)& theExtPS)
mytolv(0.0),
myIsAnalyticallyComputable(Standard_False),
myDone(Standard_False),
myNbExt(0),
myExtPS (theExtPS)
myNbExt(0)
{
}
@@ -167,8 +166,7 @@ Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt&
const Standard_Real theVmin,
const Standard_Real theVsup,
const Standard_Real theTolU,
const Standard_Real theTolV,
const Handle(Extrema_GenExtPS)& theExtPS)
const Standard_Real theTolV)
: myuinf(theUmin),
myusup(theUsup),
mytolu(theTolU),
@@ -178,8 +176,7 @@ Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt&
myS (theS),
myIsAnalyticallyComputable(Standard_False),
myDone(Standard_False),
myNbExt(0),
myExtPS (theExtPS)
myNbExt(0)
{
Initialize (theS,
theUmin,
@@ -196,8 +193,7 @@ Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt&
Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt& theP,
const Handle(GeomAdaptor_HSurfaceOfLinearExtrusion)& theS,
const Standard_Real theTolU,
const Standard_Real theTolV,
const Handle(Extrema_GenExtPS)& theExtPS)
const Standard_Real theTolV)
: myuinf(theS->FirstUParameter()),
myusup(theS->LastUParameter()),
mytolu(theTolU),
@@ -207,8 +203,7 @@ Extrema_ExtPExtS::Extrema_ExtPExtS (const gp_Pnt&
myS (theS),
myIsAnalyticallyComputable(Standard_False),
myDone(Standard_False),
myNbExt(0),
myExtPS (theExtPS)
myNbExt(0)
{
Initialize (theS,
theS->FirstUParameter(),
@@ -258,18 +253,15 @@ void Extrema_ExtPExtS::Initialize (const Handle(GeomAdaptor_HSurfaceOfLinearExtr
if (!myIsAnalyticallyComputable)
{
if (myExtPS.IsNull())
myExtPS = new Extrema_GenExtPS();
myExtPS->Initialize (theS->ChangeSurface(),
32,
32,
theUinf,
theUsup,
theVinf,
theVsup,
theTolU,
theTolV);
myExtPS.Initialize (theS->ChangeSurface(),
32,
32,
theUinf,
theUsup,
theVinf,
theVsup,
theTolU,
theTolV);
}
}
@@ -288,9 +280,11 @@ void Extrema_ExtPExtS::Perform (const gp_Pnt& P)
myNbExt = 0;
if (!myIsAnalyticallyComputable) {
myExtPS->Perform(P);
myDone = myExtPS->IsDone();
myNbExt = myExtPS->NbExt();
myExtPS.Perform(P);
myDone = myExtPS.IsDone();
// modified by NIZHNY-EAP Wed Nov 17 12:59:08 1999 ___BEGIN___
myNbExt = myExtPS.NbExt();
// modified by NIZHNY-EAP Wed Nov 17 12:59:09 1999 ___END___
return;
}
@@ -449,8 +443,10 @@ Standard_Boolean Extrema_ExtPExtS::IsDone () const { return myDone; }
Standard_Integer Extrema_ExtPExtS::NbExt () const
{
if (!IsDone()) { throw StdFail_NotDone(); }
return myNbExt;
if (myIsAnalyticallyComputable)
return myNbExt;
else
return myExtPS.NbExt();
}
//=============================================================================
@@ -466,7 +462,7 @@ Standard_Real Extrema_ExtPExtS::SquareDistance (const Standard_Integer N) const
return mySqDist[N-1];
// modified by NIZHNY-MKK Thu Sep 18 14:48:42 2003.END
else
return myExtPS->SquareDistance(N);
return myExtPS.SquareDistance(N);
}
//=============================================================================
@@ -483,7 +479,7 @@ const Extrema_POnSurf& Extrema_ExtPExtS::Point (const Standard_Integer N) const
}
// modified by NIZHNY-MKK Thu Sep 18 14:47:43 2003.END
else
return myExtPS->Point(N);
return myExtPS.Point(N);
}
//=============================================================================

View File

@@ -50,21 +50,15 @@ class Extrema_ExtPExtS : public Standard_Transient
public:
//! theExtPS is used to compute the solutions in case
//! it cannot be found analytically.
Standard_EXPORT Extrema_ExtPExtS(const Handle(Extrema_GenExtPS)& theExtPS);
Standard_EXPORT Extrema_ExtPExtS();
//! It calculates all the distances between a point
//! from gp and a Surface.
//! theExtPS is used to compute the solutions in case
//! it cannot be found analytically.
Standard_EXPORT Extrema_ExtPExtS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfLinearExtrusion)& S, const Standard_Real Umin, const Standard_Real Usup, const Standard_Real Vmin, const Standard_Real Vsup, const Standard_Real TolU, const Standard_Real TolV, const Handle(Extrema_GenExtPS)& theExtPS = NULL);
Standard_EXPORT Extrema_ExtPExtS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfLinearExtrusion)& S, const Standard_Real Umin, const Standard_Real Usup, const Standard_Real Vmin, const Standard_Real Vsup, const Standard_Real TolU, const Standard_Real TolV);
//! It calculates all the distances between a point
//! from gp and a Surface.
//! theExtPS is used to compute the solutions in case
//! it cannot be found analytically.
Standard_EXPORT Extrema_ExtPExtS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfLinearExtrusion)& S, const Standard_Real TolU, const Standard_Real TolV, const Handle(Extrema_GenExtPS)& theExtPS = NULL);
Standard_EXPORT Extrema_ExtPExtS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfLinearExtrusion)& S, const Standard_Real TolU, const Standard_Real TolV);
//! Initializes the fields of the algorithm.
Standard_EXPORT void Initialize (const Handle(GeomAdaptor_HSurfaceOfLinearExtrusion)& S, const Standard_Real Uinf, const Standard_Real Usup, const Standard_Real Vinf, const Standard_Real Vsup, const Standard_Real TolU, const Standard_Real TolV);
@@ -109,12 +103,13 @@ private:
Handle(GeomAdaptor_HSurfaceOfLinearExtrusion) myS;
gp_Vec myDirection;
gp_Ax2 myPosition;
Extrema_GenExtPS myExtPS;
Standard_Boolean myIsAnalyticallyComputable;
Standard_Boolean myDone;
Standard_Integer myNbExt;
Standard_Real mySqDist[4];
Extrema_POnSurf myPoint[4];
Handle(Extrema_GenExtPS) myExtPS;
};

View File

@@ -208,9 +208,7 @@ static Standard_Boolean IsExtremum (const Standard_Real U, const Standard_Real V
//purpose :
//=======================================================================
Extrema_ExtPRevS::Extrema_ExtPRevS(const Handle(Extrema_GenExtPS)& theExtPS)
:
myExtPS (theExtPS)
Extrema_ExtPRevS::Extrema_ExtPRevS()
{
myvinf = myvsup = 0.0;
mytolv = Precision::Confusion();
@@ -235,10 +233,7 @@ Extrema_ExtPRevS::Extrema_ExtPRevS (const gp_Pnt&
const Standard_Real theVmin,
const Standard_Real theVsup,
const Standard_Real theTolU,
const Standard_Real theTolV,
const Handle(Extrema_GenExtPS)& theExtPS)
:
myExtPS (theExtPS)
const Standard_Real theTolV)
{
Initialize (theS,
theUmin,
@@ -258,10 +253,7 @@ Extrema_ExtPRevS::Extrema_ExtPRevS (const gp_Pnt&
Extrema_ExtPRevS::Extrema_ExtPRevS (const gp_Pnt& theP,
const Handle(GeomAdaptor_HSurfaceOfRevolution)& theS,
const Standard_Real theTolU,
const Standard_Real theTolV,
const Handle(Extrema_GenExtPS)& theExtPS)
:
myExtPS (theExtPS)
const Standard_Real theTolV)
{
Initialize (theS,
theS->FirstUParameter(),
@@ -313,18 +305,15 @@ void Extrema_ExtPRevS::Initialize (const Handle(GeomAdaptor_HSurfaceOfRevolution
aNbv = 100;
}
if (myExtPS.IsNull())
myExtPS = new Extrema_GenExtPS();
myExtPS->Initialize (theS->ChangeSurface(),
aNbu,
aNbv,
theUmin,
theUsup,
theVmin,
theVsup,
theTolU,
theTolV);
myExtPS.Initialize (theS->ChangeSurface(),
aNbu,
aNbv,
theUmin,
theUsup,
theVmin,
theVsup,
theTolU,
theTolV);
}
}
//=======================================================================
@@ -337,11 +326,11 @@ void Extrema_ExtPRevS::Perform(const gp_Pnt& P)
myDone = Standard_False;
myNbExt = 0;
if (!myIsAnalyticallyComputable)
{
myExtPS->Perform(P);
myDone = myExtPS->IsDone();
myNbExt = myExtPS->NbExt();
if (!myIsAnalyticallyComputable) {
myExtPS.Perform(P);
myDone = myExtPS.IsDone();
myNbExt = myExtPS.NbExt();
return;
}
@@ -566,7 +555,7 @@ Standard_Real Extrema_ExtPRevS::SquareDistance(const Standard_Integer N) const
if (myIsAnalyticallyComputable)
return mySqDist[N-1];
else
return myExtPS->SquareDistance(N);
return myExtPS.SquareDistance(N);
}
//=======================================================================
//function : Point
@@ -582,7 +571,7 @@ const Extrema_POnSurf& Extrema_ExtPRevS::Point(const Standard_Integer N) const
if (myIsAnalyticallyComputable)
return myPoint[N-1];
else
return myExtPS->Point(N);
return myExtPS.Point(N);
}

View File

@@ -45,21 +45,16 @@ class Extrema_ExtPRevS : public Standard_Transient
public:
//! theExtPS is used to compute the solutions in case
//! it cannot be found analytically.
Standard_EXPORT Extrema_ExtPRevS(const Handle(Extrema_GenExtPS)& theExtPS = NULL);
Standard_EXPORT Extrema_ExtPRevS();
//! It calculates all the distances between a point
//! from gp and a SurfacePtr from Adaptor3d.
//! theExtPS is used to compute the solutions in case
//! it cannot be found analytically.
Standard_EXPORT Extrema_ExtPRevS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfRevolution)& S, const Standard_Real Umin, const Standard_Real Usup, const Standard_Real Vmin, const Standard_Real Vsup, const Standard_Real TolU, const Standard_Real TolV, const Handle(Extrema_GenExtPS)& theExtPS = NULL);
Standard_EXPORT Extrema_ExtPRevS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfRevolution)& S, const Standard_Real Umin, const Standard_Real Usup, const Standard_Real Vmin, const Standard_Real Vsup, const Standard_Real TolU, const Standard_Real TolV);
//! It calculates all the distances between a point
//! from gp and a SurfacePtr from Adaptor3d.
//! theExtPS is used to compute the solutions in case
//! it cannot be found analytically.
Standard_EXPORT Extrema_ExtPRevS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfRevolution)& S, const Standard_Real TolU, const Standard_Real TolV, const Handle(Extrema_GenExtPS)& theExtPS = NULL);
Standard_EXPORT Extrema_ExtPRevS(const gp_Pnt& P, const Handle(GeomAdaptor_HSurfaceOfRevolution)& S, const Standard_Real TolU, const Standard_Real TolV);
Standard_EXPORT void Initialize (const Handle(GeomAdaptor_HSurfaceOfRevolution)& S, const Standard_Real Umin, const Standard_Real Usup, const Standard_Real Vmin, const Standard_Real Vsup, const Standard_Real TolU, const Standard_Real TolV);
@@ -95,12 +90,13 @@ private:
Standard_Real myvsup;
Standard_Real mytolv;
gp_Ax2 myPosition;
Extrema_GenExtPS myExtPS;
Standard_Boolean myIsAnalyticallyComputable;
Standard_Boolean myDone;
Standard_Integer myNbExt;
Standard_Real mySqDist[8];
Extrema_POnSurf myPoint[8];
Handle(Extrema_GenExtPS) myExtPS;
};

View File

@@ -157,8 +157,12 @@ Extrema_ExtPS::Extrema_ExtPS (const gp_Pnt& theP,
const Adaptor3d_Surface& theS,
const Standard_Real theTolU,
const Standard_Real theTolV,
const Extrema_ExtFlag theTarget)
const Extrema_ExtFlag theF,
const Extrema_ExtAlgo theA)
{
myExtPS.SetFlag (theF);
myExtPS.SetAlgo (theA);
Initialize (theS,
theS.FirstUParameter(),
theS.LastUParameter(),
@@ -167,8 +171,6 @@ Extrema_ExtPS::Extrema_ExtPS (const gp_Pnt& theP,
theTolU,
theTolV);
myExtPS->SetTarget (theTarget);
Perform (theP);
}
@@ -185,8 +187,12 @@ Extrema_ExtPS::Extrema_ExtPS (const gp_Pnt& theP,
const Standard_Real theVsup,
const Standard_Real theTolU,
const Standard_Real theTolV,
const Extrema_ExtFlag theTarget)
const Extrema_ExtFlag theF,
const Extrema_ExtAlgo theA)
{
myExtPS.SetFlag (theF);
myExtPS.SetAlgo (theA);
Initialize (theS,
theUinf,
theUsup,
@@ -195,8 +201,6 @@ Extrema_ExtPS::Extrema_ExtPS (const gp_Pnt& theP,
theTolU,
theTolV);
myExtPS->SetTarget (theTarget);
Perform (theP);
}
@@ -247,10 +251,7 @@ void Extrema_ExtPS::Initialize (const Adaptor3d_Surface& theS,
if(bUIsoIsDeg) nbU = 300;
if(bVIsoIsDeg) nbV = 300;
if (myExtPS.IsNull())
myExtPS = new Extrema_GenExtPS();
myExtPS->Initialize(*myS, nbU, nbV, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
myExtPS.Initialize(*myS, nbU, nbV, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
myExtPExtS.Nullify();
myExtPRevS.Nullify();
@@ -291,7 +292,7 @@ void Extrema_ExtPS::Perform(const gp_Pnt& thePoint)
Handle(GeomAdaptor_HSurfaceOfLinearExtrusion) aS (new GeomAdaptor_HSurfaceOfLinearExtrusion (
GeomAdaptor_SurfaceOfLinearExtrusion (myS->BasisCurve(), myS->Direction())));
myExtPExtS = new Extrema_ExtPExtS (thePoint, aS, myuinf, myusup, myvinf, myvsup, mytolu, mytolv, myExtPS);
myExtPExtS = new Extrema_ExtPExtS (thePoint, aS, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
}
else
{
@@ -317,7 +318,7 @@ void Extrema_ExtPS::Perform(const gp_Pnt& thePoint)
Handle(GeomAdaptor_HSurfaceOfRevolution) aS (new GeomAdaptor_HSurfaceOfRevolution (
GeomAdaptor_SurfaceOfRevolution (myS->BasisCurve(), myS->AxeOfRevolution())));
myExtPRevS = new Extrema_ExtPRevS (thePoint, aS, myuinf, myusup, myvinf, myvsup, mytolu, mytolv, myExtPS);
myExtPRevS = new Extrema_ExtPRevS (thePoint, aS, myuinf, myusup, myvinf, myvsup, mytolu, mytolv);
}
else
{
@@ -338,13 +339,13 @@ void Extrema_ExtPS::Perform(const gp_Pnt& thePoint)
default:
{
myExtPS->Perform (thePoint);
myDone = myExtPS->IsDone();
myExtPS.Perform (thePoint);
myDone = myExtPS.IsDone();
if (myDone)
{
for (Standard_Integer anIdx = 1; anIdx <= myExtPS->NbExt(); ++anIdx)
for (Standard_Integer anIdx = 1; anIdx <= myExtPS.NbExt(); ++anIdx)
{
TreatSolution (myExtPS->Point (anIdx), myExtPS->SquareDistance (anIdx));
TreatSolution (myExtPS.Point (anIdx), myExtPS.SquareDistance (anIdx));
}
}
return;
@@ -410,8 +411,10 @@ void Extrema_ExtPS::TrimmedSquareDistances(Standard_Real& dUfVf,
void Extrema_ExtPS::SetFlag(const Extrema_ExtFlag F)
{
if (myExtPS.IsNull())
myExtPS = new Extrema_GenExtPS();
myExtPS->SetTarget(F);
myExtPS.SetFlag(F);
}
void Extrema_ExtPS::SetAlgo(const Extrema_ExtAlgo A)
{
myExtPS.SetAlgo(A);
}

Some files were not shown because too many files have changed in this diff Show More