{ Free Pascal port of the OpenPTC C++ library. Copyright (C) 2001-2003 Nikolay Nikolov (nickysn@users.sourceforge.net) Original C++ version by Glenn Fiedler (ptc@gaffer.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA } { $INLINE ON} Class Function TPTCClipper.clip(Const _area, _clip : TPTCArea) : TPTCArea; Var left, top, right, bottom : Integer; clip_left, clip_top, clip_right, clip_bottom : Integer; Begin { get in coordinates } left := _area.left; top := _area.top; right := _area.right; bottom := _area.bottom; { get clip coordinates } clip_left := _clip.left; clip_top := _clip.top; clip_right := _clip.right; clip_bottom := _clip.bottom; { clip left } If left < clip_left Then left := clip_left; If left > clip_right Then left := clip_right; { clip top } If top < clip_top Then top := clip_top; If top > clip_bottom Then top := clip_bottom; { clip right } If right < clip_left Then right := clip_left; If right > clip_right Then right := clip_right; { clip bottom } If bottom < clip_top Then bottom := clip_top; If bottom > clip_bottom Then bottom := clip_bottom; clip := TPTCArea.Create(left, top, right, bottom); End; { clip floating point area against a floating point clip area } Procedure TPTCClipper_clip(Var left, top, right, bottom : Real; clip_left, clip_top, clip_right, clip_bottom : Real);{ Inline;} Begin { clip left } If left < clip_left Then left := clip_left; If left > clip_right Then left := clip_right; { clip top } If top < clip_top Then top := clip_top; If top > clip_bottom Then top := clip_bottom; { clip right } If right < clip_left Then right := clip_left; If right > clip_right Then right := clip_right; { clip bottom } If bottom < clip_top Then bottom := clip_top; If bottom > clip_bottom Then bottom := clip_bottom; End; { clip floating point area against clip area } Procedure TPTCClipper_clip(Var left, top, right, bottom : Real; Const _clip : TPTCArea);{ Inline;} Var clip_left, clip_top, clip_right, clip_bottom : Real; Begin { get floating point clip area } clip_left := _clip.left; clip_top := _clip.top; clip_right := _clip.right; clip_bottom := _clip.bottom; { clip floating point area against floating point clip area } TPTCClipper_clip(left, top, right, bottom, clip_left, clip_top, clip_right, clip_bottom); End; { snap a floating point area to integer coordinates } Procedure TPTCClipper_round(Var left, top, right, bottom : Real);{ Inline;} Begin left := Round(left); top := Round(top); right := Round(right); bottom := Round(bottom); End; Class Procedure TPTCClipper.clip(Const source, clip_source, clipped_source, destination, clip_destination, clipped_destination : TPTCArea); Var tmp1, tmp2 : TPTCArea; source_left, source_top, source_right, source_bottom : Real; clipped_source_left, clipped_source_top, clipped_source_right, clipped_source_bottom : Real; source_delta_left, source_delta_top, source_delta_right, source_delta_bottom : Real; source_to_destination_x, source_to_destination_y : Real; destination_left, destination_top, destination_right, destination_bottom : Real; adjusted_destination_left, adjusted_destination_top, adjusted_destination_right, adjusted_destination_bottom : Real; clipped_destination_left, clipped_destination_top, clipped_destination_right, clipped_destination_bottom : Real; destination_delta_left, destination_delta_top, destination_delta_right, destination_delta_bottom : Real; destination_to_source_x, destination_to_source_y : Real; adjusted_source_left, adjusted_source_top, adjusted_source_right, adjusted_source_bottom : Real; Begin tmp1 := Nil; tmp2 := Nil; Try { expand source area to floating point } source_left := source.left; source_top := source.top; source_right := source.right; source_bottom := source.bottom; { setup clipped source area } clipped_source_left := source_left; clipped_source_top := source_top; clipped_source_right := source_right; clipped_source_bottom := source_bottom; { perform clipping on floating point source area } TPTCClipper_clip(clipped_source_left, clipped_source_top, clipped_source_right, clipped_source_bottom, clip_source); { check for early source area clipping exit } If (clipped_source_left = clipped_source_right) Or (clipped_source_top = clipped_source_bottom) Then Begin { clipped area is zero } tmp1 := TPTCArea.Create(0, 0, 0, 0); clipped_source.ASSign(tmp1); clipped_destination.ASSign(tmp1); Exit; End; { calculate deltas in source clip } source_delta_left := clipped_source_left - source_left; source_delta_top := clipped_source_top - source_top; source_delta_right := clipped_source_right - source_right; source_delta_bottom := clipped_source_bottom - source_bottom; { calculate ratio of source area to destination area } source_to_destination_x := destination.width / source.width; source_to_destination_y := destination.height / source.height; { expand destination area to floating point } destination_left := destination.left; destination_top := destination.top; destination_right := destination.right; destination_bottom := destination.bottom; { calculate adjusted destination area } adjusted_destination_left := destination_left + source_delta_left * source_to_destination_x; adjusted_destination_top := destination_top + source_delta_top * source_to_destination_y; adjusted_destination_right := destination_right + source_delta_right * source_to_destination_x; adjusted_destination_bottom := destination_bottom + source_delta_bottom * source_to_destination_y; { setup clipped destination area } clipped_destination_left := adjusted_destination_left; clipped_destination_top := adjusted_destination_top; clipped_destination_right := adjusted_destination_right; clipped_destination_bottom := adjusted_destination_bottom; { perform clipping on floating point destination area } TPTCClipper_clip(clipped_destination_left, clipped_destination_top, clipped_destination_right, clipped_destination_bottom, clip_destination); { check for early destination area clipping exit } If (clipped_destination_left = clipped_destination_right) Or (clipped_destination_top = clipped_destination_bottom) Then Begin { clipped area is zero } tmp1 := TPTCArea.Create(0, 0, 0, 0); clipped_source.ASSign(tmp1); clipped_destination.ASSign(tmp1); Exit; End; { calculate deltas in destination clip } destination_delta_left := clipped_destination_left - adjusted_destination_left; destination_delta_top := clipped_destination_top - adjusted_destination_top; destination_delta_right := clipped_destination_right - adjusted_destination_right; destination_delta_bottom := clipped_destination_bottom - adjusted_destination_bottom; { calculate ratio of destination area to source area } destination_to_source_x := 1 / source_to_destination_x; destination_to_source_y := 1 / source_to_destination_y; { calculate adjusted source area } adjusted_source_left := clipped_source_left + destination_delta_left * destination_to_source_x; adjusted_source_top := clipped_source_top + destination_delta_top * destination_to_source_y; adjusted_source_right := clipped_source_right + destination_delta_right * destination_to_source_x; adjusted_source_bottom := clipped_source_bottom + destination_delta_bottom * destination_to_source_y; { assign adjusted source to clipped source } clipped_source_left := adjusted_source_left; clipped_source_top := adjusted_source_top; clipped_source_right := adjusted_source_right; clipped_source_bottom := adjusted_source_bottom; { round clipped areas to integer coordinates } TPTCClipper_round(clipped_source_left, clipped_source_top, clipped_source_right, clipped_source_bottom); TPTCClipper_round(clipped_destination_left, clipped_destination_top, clipped_destination_right, clipped_destination_bottom); { construct clipped area rectangles from rounded floating point areas } tmp1 := TPTCArea.Create(Trunc(clipped_source_left), Trunc(clipped_source_top), Trunc(clipped_source_right), Trunc(clipped_source_bottom)); tmp2 := TPTCArea.Create(Trunc(clipped_destination_left), Trunc(clipped_destination_top), Trunc(clipped_destination_right), Trunc(clipped_destination_bottom)); clipped_source.ASSign(tmp1); clipped_destination.ASSign(tmp2); Finally tmp1.Free; tmp2.Free; End; End;