00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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
00073 if (line(2)%x == line(1)%x) then
00074
00075
00076
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
00087
00088 u = (point%x - line(1)%x) / (line(2)%x - line(1)%x)
00089
00090 if (abs(u) > 1 + epsilon_dble) then
00091
00092
00093 point_is_on_line_dble = .false.
00094 else
00095
00096
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
00102 point_is_on_line_dble = .false.
00103 else
00104
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
00119 if (line(2)%x == line(1)%x) then
00120
00121
00122
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
00133
00134 u = (point%x - line(1)%x) / (line(2)%x - line(1)%x)
00135
00136 if (abs(u) > 1 + epsilon_real) then
00137
00138
00139 point_is_on_line_real = .false.
00140 else
00141
00142
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
00148 point_is_on_line_real = .false.
00149 else
00150
00151 point_is_on_line_real = .true.
00152 endif
00153 endif
00154 endif
00155
00156 end function point_is_on_line_real
00157
00158
00159
00160
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
00169
00170
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
00181 if (e2%x == 0) then
00182
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
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
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
00233
00234
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
00245 if (e2%x == 0) then
00246
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
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
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
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
00301 if (inside_ABC .neqv. inside_ACD) then
00302
00303
00304 point_is_in_quadrangle_dble = .true.
00305 else if (.not.(inside_ABC .or. inside_ACD)) then
00306
00307
00308 point_is_in_quadrangle_dble = .false.
00309 else
00310
00311
00312 if (point_is_on_line_dble(point, (/quadrangle(1), quadrangle(3)/))) then
00313
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
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
00325
00326
00327 point_is_in_quadrangle_dble = .false.
00328 else
00329
00330 point_is_in_quadrangle_dble = .true.
00331 endif
00332 endif
00333 else
00334
00335 if (point_is_in_triangle_dble(quadrangle(4), quadrangle(1:3))) then
00336
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
00340 point_is_in_quadrangle_dble = .true.
00341 else
00342 point_is_in_quadrangle_dble = .false.
00343 endif
00344 else
00345
00346 if (point_is_on_line_dble(point, quadrangle(2:3)) .or. &
00347 point_is_on_line_dble(point, quadrangle(1:2))) then
00348
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
00370 if (inside_ABC .neqv. inside_ACD) then
00371
00372
00373 point_is_in_quadrangle_real = .true.
00374 else if (.not.(inside_ABC .or. inside_ACD)) then
00375
00376
00377 point_is_in_quadrangle_real = .false.
00378 else
00379
00380
00381 if (point_is_on_line_real(point, (/quadrangle(1), quadrangle(3)/))) then
00382
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
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
00394
00395
00396 point_is_in_quadrangle_real = .false.
00397 else
00398
00399 point_is_in_quadrangle_real = .true.
00400 endif
00401 endif
00402 else
00403
00404 if (point_is_in_triangle_real(quadrangle(4), quadrangle(1:3))) then
00405
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
00409 point_is_in_quadrangle_real = .true.
00410 else
00411 point_is_in_quadrangle_real = .false.
00412 endif
00413 else
00414
00415 if (point_is_on_line_real(point, quadrangle(2:3)) .or. &
00416 point_is_on_line_real(point, quadrangle(1:2))) then
00417
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