psmile_geometry.F90

Go to the documentation of this file.
00001 !-----------------------------------------------------------------------
00002 ! Copyright 2010, DKRZ, Hamburg, Germany.
00003 ! All rights reserved. Use is subject to OASIS4 license terms.
00004 !-----------------------------------------------------------------------
00005 !
00006 ! !DESCRIPTION:
00007 !
00008 ! Module psmile_geometry contains function for testing whether a point
00009 ! is on a line, triangle, or quadrangle
00010 !
00011 !
00012 ! !REVISION HISTORY:
00013 !
00014 !   Date      Programmer   Description
00015 ! ----------  ----------   -----------
00016 ! 16.09.10    M. Hanke     created
00017 !
00018 !----------------------------------------------------------------------
00019 !
00020 !  $Id: psmile_geometry.F90 2727 2010-11-12 13:37:17Z hanke $
00021 !  $Author: hanke $
00022 !
00023 !----------------------------------------------------------------------
00024 
00025 
00026    module psmile_geometry
00027 
00028       use psmile, only : point_dble, point_real
00029 
00030       implicit none
00031 
00032       double precision, parameter :: epsilon_dble = 1.0d-13
00033       real, parameter             :: epsilon_real = 1.0d-13
00034 
00035       private ! by default everything is private in this module
00036 
00037       interface point_is_on_line
00038          module procedure point_is_on_line_dble, &
00039                           point_is_on_line_real
00040       end interface
00041 
00042       interface point_is_in_triangle
00043          module procedure point_is_in_triangle_dble, &
00044                           point_is_in_triangle_real
00045       end interface
00046 
00047       interface point_is_in_quadrangle
00048          module procedure point_is_in_quadrangle_dble, &
00049                           point_is_in_quadrangle_real
00050       end interface
00051 
00052       interface intersect
00053          module procedure rectangular_shapes_intersect_int
00054       end interface
00055 
00056       public :: point_is_on_line
00057       public :: point_is_in_triangle
00058       public :: point_is_in_quadrangle
00059       public :: epsilon_dble
00060       public :: epsilon_real
00061       public :: intersect
00062 
00063       contains
00064 
00065          ! returns true if point is on line
00066          logical function point_is_on_line_dble(point, line)
00067             type (point_dble), intent(in) :: point
00068             type (point_dble), intent(in) :: line(2)
00069 
00070             double precision :: u, norm_err
00071 
00072             ! if A and B have the same x coordinate
00073             if (line(2)%x == line(1)%x) then
00074 
00075                ! if A, B and P have the same x coordinate and
00076                ! P is between A and B
00077                if ( point%x == line(1)%x .and. &
00078                   (point%y >= line(1)%y .and. point%y <= line(2)%y .or. &
00079                   point%y <= line(1)%y .and. point%y >= line(2)%y)) then
00080                   point_is_on_line_dble = .true.
00081                else
00082                   point_is_on_line_dble = .false.
00083                endif
00084             else
00085 
00086                !formula: A + (B - A) * u = P
00087                ! u = (Px - Ax) / (Bx - Ax)
00088                u = (point%x - line(1)%x) / (line(2)%x - line(1)%x)
00089 
00090                if (abs(u) > 1 + epsilon_dble) then
00091                   ! point P might be on a line which goes through AB
00092                   ! but is outside of the range of AB
00093                   point_is_on_line_dble = .false.
00094                else
00095                   ! computes normalised error of solution u
00096                   ! error = |(Ay + (By - Ay) * u - Py) / Py| = 0
00097                   norm_err = line(1)%y + (line(2)%y - line(1)%y) * u - point%y
00098                   if (point%y /= 0.0d0) norm_err = norm_err / point%y
00099 
00100                   if (abs(norm_err) > epsilon_dble) then
00101                      ! point is not on line AB
00102                      point_is_on_line_dble = .false.
00103                   else
00104                      ! point is on line AB
00105                      point_is_on_line_dble = .true.
00106                   endif
00107                endif
00108             endif
00109 
00110          end function point_is_on_line_dble
00111 
00112          logical function point_is_on_line_real(point, line)
00113             type (point_real), intent(in) :: point
00114             type (point_real), intent(in) :: line(2)
00115 
00116             real :: u, norm_err
00117 
00118             ! if A and B have the same x coordinate
00119             if (line(2)%x == line(1)%x) then
00120 
00121                ! if A, B and P have the same x coordinate and
00122                ! P is between A and B
00123                if ( point%x == line(1)%x .and. &
00124                   (point%y >= line(1)%y .and. point%y <= line(2)%y .or. &
00125                   point%y <= line(1)%y .and. point%y >= line(2)%y)) then
00126                   point_is_on_line_real = .true.
00127                else
00128                   point_is_on_line_real = .false.
00129                endif
00130             else
00131 
00132                !formula: A + (B - A) * u = P
00133                ! u = (Px - Ax) / (Bx - Ax)
00134                u = (point%x - line(1)%x) / (line(2)%x - line(1)%x)
00135 
00136                if (abs(u) > 1 + epsilon_real) then
00137                   ! point P might be on a line which goes through AB
00138                   ! but is outside of the range of AB
00139                   point_is_on_line_real = .false.
00140                else
00141                   ! computes normalised error of solution u
00142                   ! error = |(Ay + (By - Ay) * u - Py) / Py| = 0
00143                   norm_err = line(1)%y + (line(2)%y - line(1)%y) * u - point%y
00144                   if (point%y /= 0.0d0) norm_err = norm_err / point%y
00145 
00146                   if (abs(norm_err) > epsilon_real) then
00147                      ! point is not on line AB
00148                      point_is_on_line_real = .false.
00149                   else
00150                      ! point is on line AB
00151                      point_is_on_line_real = .true.
00152                   endif
00153                endif
00154             endif
00155 
00156          end function point_is_on_line_real
00157 
00158          !algorithm is taken from: http://www.drdobbs.com/184404201?pgno=2
00159          !it is based on barycentric coordinates
00160          !elemental
00161          logical function point_is_in_triangle_dble(point, triangle)
00162             type (point_dble), intent(in) :: point
00163             type (point_dble), intent(in) :: triangle(3)
00164 
00165             type (point_dble) :: e1, e2, e3
00166             double precision  :: u, v, d
00167 
00168             ! formula:
00169             ! (P-A) = (C-A)*u + (B-A)*v
00170             ! e1    = e3   *u + e2   *v
00171 
00172             e1%x = point%x - triangle(1)%x
00173             e2%x = triangle(2)%x - triangle(1)%x
00174             e3%x = triangle(3)%x - triangle(1)%x
00175 
00176             e1%y = point%y - triangle(1)%y
00177             e2%y = triangle(2)%y - triangle(1)%y
00178             e3%y = triangle(3)%y - triangle(1)%y
00179 
00180             ! if A and B have the same x coordinate
00181             if (e2%x == 0) then
00182                ! if A, B and C have the same x coordinate
00183                if (e3%x == 0) then
00184                   point_is_in_triangle_dble = point_is_on_line_dble(point, triangle(1:2)) .or. &
00185                                              point_is_on_line_dble(point, (/triangle(1), triangle(3)/))
00186                   return
00187                endif
00188                u = e1%x / e3%x
00189                if (u < - epsilon_dble .or. u > 1 + epsilon_dble) then
00190                   point_is_in_triangle_dble = .false.
00191                   return
00192                endif
00193                ! if A and B have the same x and y coordinates
00194                if (e2%y == 0) then
00195                   point_is_in_triangle_dble = point_is_on_line_dble(point, (/triangle(1), triangle(3)/))
00196                   return
00197                endif
00198                v = (e1%y - e3%y * u) / e2%y
00199                if (v < - epsilon_dble) then
00200                   point_is_in_triangle_dble = .false.
00201                   return
00202                endif
00203             else ! A and B have different x coordinates
00204                d = e3%y * e2%x - e3%x * e2%y
00205                if (d == 0) then
00206                   point_is_in_triangle_dble = .false.
00207                   return
00208                endif;
00209                u = (e1%y * e2%x - e1%x * e2%y) / d
00210                if (u < - epsilon_dble .or. u > 1 + epsilon_dble) then
00211                   point_is_in_triangle_dble = .false.
00212                   return
00213                endif
00214                v = (e1%x - e3%x * u) / e2%x
00215                if (v <  - epsilon_dble) then
00216                   point_is_in_triangle_dble = .false.
00217                   return
00218                endif
00219             endif
00220 
00221             point_is_in_triangle_dble = (u + v <= 1 + epsilon_dble)
00222 
00223          end function point_is_in_triangle_dble
00224 
00225          logical function point_is_in_triangle_real(point, triangle)
00226             type (point_real), intent(in) :: point
00227             type (point_real), intent(in) :: triangle(3)
00228 
00229             type (point_real) :: e1, e2, e3
00230             real              :: u, v, d
00231 
00232             ! formula:
00233             ! (P-A) = (C-A)*u + (B-A)*v
00234             ! e1    = e3   *u + e2   *v
00235 
00236             e1%x = point%x - triangle(1)%x
00237             e2%x = triangle(2)%x - triangle(1)%x
00238             e3%x = triangle(3)%x - triangle(1)%x
00239 
00240             e1%y = point%y - triangle(1)%y
00241             e2%y = triangle(2)%y - triangle(1)%y
00242             e3%y = triangle(3)%y - triangle(1)%y
00243 
00244             ! if A and B have the same x coordinate
00245             if (e2%x == 0) then
00246                ! if A, B and C have the same x coordinate
00247                if (e3%x == 0) then
00248                   point_is_in_triangle_real = point_is_on_line_real(point, triangle(1:2)) .or. &
00249                                              point_is_on_line_real(point, (/triangle(1), triangle(3)/))
00250                   return
00251                endif
00252                u = e1%x / e3%x
00253                if (u < - epsilon_real .or. u > 1 + epsilon_real) then
00254                   point_is_in_triangle_real = .false.
00255                   return
00256                endif
00257                ! if A and B have the same x and y coordinates
00258                if (e2%y == 0) then
00259                   point_is_in_triangle_real = point_is_on_line_real(point, (/triangle(1), triangle(3)/))
00260                   return
00261                endif
00262                v = (e1%y - e3%y * u) / e2%y
00263                if (v < - epsilon_real) then
00264                   point_is_in_triangle_real = .false.
00265                   return
00266                endif
00267             else ! A and B have different x coordinates
00268                d = e3%y * e2%x - e3%x * e2%y
00269                if (d == 0) then
00270                   point_is_in_triangle_real = .false.
00271                   return
00272                endif;
00273                u = (e1%y * e2%x - e1%x * e2%y) / d
00274                if (u < - epsilon_real .or. u > 1 + epsilon_real) then
00275                   point_is_in_triangle_real = .false.
00276                   return
00277                endif
00278                v = (e1%x - e3%x * u) / e2%x
00279                if (v <  - epsilon_real) then
00280                   point_is_in_triangle_real = .false.
00281                   return
00282                endif
00283             endif
00284 
00285             point_is_in_triangle_real = (u + v <= 1 + epsilon_real)
00286 
00287          end function point_is_in_triangle_real
00288 
00289          !elemental
00290          logical function point_is_in_quadrangle_dble(point, quadrangle)
00291             type (point_dble), intent(in) :: point
00292             type (point_dble), intent(in) :: quadrangle(4)
00293 
00294             logical :: inside_ABC, inside_ACD
00295 
00296             inside_ABC = point_is_in_triangle_dble(point, quadrangle(1:3))
00297             inside_ACD = point_is_in_triangle_dble(point, &
00298                (/quadrangle(1), quadrangle(3), quadrangle(4)/))
00299 
00300             !neqv == xor
00301             if (inside_ABC .neqv. inside_ACD) then
00302                ! standard in-case:
00303                ! point is either in triangle ABC or in triangle ACD
00304                point_is_in_quadrangle_dble = .true.
00305             else if (.not.(inside_ABC .or. inside_ACD)) then
00306                ! standard out-case:
00307                ! point is neither in triangle ABC or in triangle ACD
00308                point_is_in_quadrangle_dble = .false.
00309             else
00310                ! point is in both triangles
00311                ! the point lies directly on line AC and/or the quadrangle is concave
00312                if (point_is_on_line_dble(point, (/quadrangle(1), quadrangle(3)/))) then
00313                   ! the point is on the line AC
00314                   if (point%x == quadrangle(1)%x .and. point%y == quadrangle(1)%y .or. &
00315                      point%x == quadrangle(2)%x .and. point%y == quadrangle(2)%y .or. &
00316                      point%x == quadrangle(3)%x .and. point%y == quadrangle(3)%y .or. &
00317                      point%x == quadrangle(4)%x .and. point%y == quadrangle(4)%y) then
00318                      ! point is directly on either A, B, C or D
00319                      point_is_in_quadrangle_dble = .true.
00320                   else
00321                      if (point_is_in_triangle_dble(quadrangle(4), quadrangle(1:3)) .or. &
00322                         point_is_in_triangle_dble(quadrangle(2), &
00323                            (/quadrangle(1), quadrangle(3), quadrangle(4)/))) then
00324                         ! the quadrangle is concave (either D lies in ABC or B lies in ACD)
00325                         ! cases were A is in BCD or C is in ABD are no problem for this algorithm
00326                         ! and are therefore not especially handled here
00327                         point_is_in_quadrangle_dble = .false.
00328                      else
00329                         ! the quadrangle is convex
00330                         point_is_in_quadrangle_dble = .true.
00331                      endif
00332                   endif
00333                else
00334                   ! the quadrangle has to be concave
00335                   if (point_is_in_triangle_dble(quadrangle(4), quadrangle(1:3))) then
00336                      ! point D is in ABC
00337                      if (point_is_on_line_dble(point, (/quadrangle(1), quadrangle(4)/)) .or. &
00338                         point_is_on_line_dble(point, quadrangle(3:4))) then
00339                         ! point is either on line AD or CD
00340                         point_is_in_quadrangle_dble = .true.
00341                      else
00342                         point_is_in_quadrangle_dble = .false.
00343                      endif
00344                   else
00345                      ! point B is in ACD
00346                      if (point_is_on_line_dble(point, quadrangle(2:3)) .or. &
00347                         point_is_on_line_dble(point, quadrangle(1:2))) then
00348                         ! point is either on line AB or BC
00349                         point_is_in_quadrangle_dble = .true.
00350                      else
00351                         point_is_in_quadrangle_dble = .false.
00352                      endif
00353                   endif
00354                endif
00355             endif
00356 
00357          end function point_is_in_quadrangle_dble
00358 
00359          logical function point_is_in_quadrangle_real(point, quadrangle)
00360             type (point_real), intent(in) :: point
00361             type (point_real), intent(in) :: quadrangle(4)
00362 
00363             logical :: inside_ABC, inside_ACD
00364 
00365             inside_ABC = point_is_in_triangle_real(point, quadrangle(1:3))
00366             inside_ACD = point_is_in_triangle_real(point, &
00367                (/quadrangle(1), quadrangle(3), quadrangle(4)/))
00368 
00369             !neqv == xor
00370             if (inside_ABC .neqv. inside_ACD) then
00371                ! standard in-case:
00372                ! point is either in triangle ABC or in triangle ACD
00373                point_is_in_quadrangle_real = .true.
00374             else if (.not.(inside_ABC .or. inside_ACD)) then
00375                ! standard out-case:
00376                ! point is neither in triangle ABC or in triangle ACD
00377                point_is_in_quadrangle_real = .false.
00378             else
00379                ! point is in both triangles
00380                ! the point lies directly on line AC and/or the quadrangle is concave
00381                if (point_is_on_line_real(point, (/quadrangle(1), quadrangle(3)/))) then
00382                   ! the point is on the line AC
00383                   if (point%x == quadrangle(1)%x .and. point%y == quadrangle(1)%y .or. &
00384                       point%x == quadrangle(2)%x .and. point%y == quadrangle(2)%y .or. &
00385                       point%x == quadrangle(3)%x .and. point%y == quadrangle(3)%y .or. &
00386                       point%x == quadrangle(4)%x .and. point%y == quadrangle(4)%y) then
00387                      ! point is directly on either A, B, C or D
00388                      point_is_in_quadrangle_real = .true.
00389                   else
00390                      if (point_is_in_triangle_real(quadrangle(4), quadrangle(1:3)) .or. &
00391                          point_is_in_triangle_real(quadrangle(2), &
00392                            (/quadrangle(1), quadrangle(3), quadrangle(4)/))) then
00393                         ! the quadrangle is concave (either D lies in ABC or B lies in ACD)
00394                         ! cases were A is in BCD or C is in ABD are no problem for this algorithm
00395                         ! and are therefore not especially handled here
00396                         point_is_in_quadrangle_real = .false.
00397                      else
00398                         ! the quadrangle is convex
00399                         point_is_in_quadrangle_real = .true.
00400                      endif
00401                   endif
00402                else
00403                   ! the quadrangle has to be concave
00404                   if (point_is_in_triangle_real(quadrangle(4), quadrangle(1:3))) then
00405                      ! point D is in ABC
00406                      if (point_is_on_line_real(point, (/quadrangle(1), quadrangle(4)/)) .or. &
00407                          point_is_on_line_real(point, quadrangle(3:4))) then
00408                         ! point is either on line AD or CD
00409                         point_is_in_quadrangle_real = .true.
00410                      else
00411                         point_is_in_quadrangle_real = .false.
00412                      endif
00413                   else
00414                      ! point B is in ACD
00415                      if (point_is_on_line_real(point, quadrangle(2:3)) .or. &
00416                          point_is_on_line_real(point, quadrangle(1:2))) then
00417                         ! point is either on line AB or BC
00418                         point_is_in_quadrangle_real = .true.
00419                      else
00420                         point_is_in_quadrangle_real = .false.
00421                      endif
00422                   endif
00423                endif
00424             endif
00425 
00426          end function point_is_in_quadrangle_real
00427 
00428          logical function rectangular_shapes_intersect_int (a, b)
00429             integer, intent(in) :: a(:,:), b(:,:)
00430 
00431             integer :: i
00432 
00433 #ifdef PRISM_ASSERTION
00434             if (size (a, 1) /= 2 .or. size (b, 1) /= 2) then
00435                call psmile_assert (__FILE__, __LINE__, &
00436                   "wrong first dimension of argument a or b in rectangles_cuboids_intersect_int")
00437             endif
00438             if (size (a,2) /= size (b,2)) then
00439                call psmile_assert (__FILE__, __LINE__, &
00440                   "none matching arguments in function rectangles_cuboids_intersect_int")
00441             endif
00442 #endif
00443             rectangular_shapes_intersect_int = .not. any (a(1,:) > b(2,:) .or. a(2,:) < b(1,:))
00444          end function rectangular_shapes_intersect_int
00445 
00446    end module psmile_geometry

Generated on 18 Mar 2011 for Oasis4 by  doxygen 1.6.1