{ * Copyright 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * Original Author: Sean Owen * Delphi Implementation by E. Spelt and K. Gossens } unit ZXing.ResultPoint; interface uses System.SysUtils, ZXing.Common.Detector.MathUtils; type /// /// To mimic "garbage collection" (or ARC) with old-gen compilers we have to use /// interfaces. IResultPoint is the interface that maps TResultPoint which is now /// implemented as a TInterfacedObject descendant which supports automatic deallocation /// based on reference counting of interface variables. /// See ZXing.ResultPointImplementation to see the actual implementation of this interface. /// since we are using automatic reference counting, we don't need the Clone method any more. /// IResultPoint = interface ['{1E60EDAB-0387-440C-9D8E-4E0CC772C820}'] // property accessors, for interfaces, MUST be functions or procedures (interfaces cannot contain data) procedure SetX(const AValue: Single); procedure SetY(const AValue: Single); function GetX: Single; function GetY: Single; function Equals(other: TObject): Boolean; function GetHashCode(): Integer; function ToString(): String; property x: Single read GetX write SetX; property y: Single read GetY write SetY; end; /// /// in order to implement TResultPoint as an interface all static methods /// have been moved in this static class. /// this class contains also the CreateResultPoint method that must be used /// in place of the actual class constructor /// TResultPointHelpers = class protected /// /// Returns the z component of the cross product between vectors BC and BA. /// class function crossProductZ(const pointA, pointB, pointC: IResultPoint): Single; static; public /// /// Initializes a new instance of and returns /// its interface /// class function CreateResultPoint:IResultPoint; overload; /// /// Initializes a new instance of and returns /// its interface /// /// The x. /// The y. class function CreateResultPoint(const pX, pY: Single):IResultPoint; overload; /// /// Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC and /// BC is less than AC and the angle between BC and BA is less than 180 degrees. /// /// array of three to order class procedure orderBestPatterns(const patterns : TArray); static; /// /// calculates the distance between two points /// /// first pattern /// second pattern /// /// distance between two points /// class function distance(const pattern1, pattern2: IResultPoint) : Single; static; end; /// Callback which is invoked when a possible result point (significant /// point in the barcode image such as a corner) is found. /// /// /// /// TResultPointCallback = procedure(const point: IResultPoint) of object; TResultPointEventObject = class(TObject) private FResultPointCallback: TResultPointCallback; public constructor Create(const AEvent: TResultPointCallback); property Event: TResultPointCallback read FResultPointCallback; end; implementation uses ZXing.ResultPointImplementation; class function TResultPointHelpers.CreateResultPoint:IResultPoint; begin result := ZXing.ResultPointImplementation.NewResultPoint; end; class function TResultPointHelpers.CreateResultPoint(const pX, pY: Single):IResultPoint; begin result := ZXing.ResultPointImplementation.NewResultPoint(px,py); end; class function TResultPointHelpers.crossProductZ(const pointA, pointB, pointC: IResultPoint): Single; var bX, bY: Single; begin bX := pointB.x; bY := pointB.y; Result := ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); end; class function TResultPointHelpers.distance(const pattern1, pattern2: IResultPoint): Single; begin Result := TMathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y); end; class procedure TResultPointHelpers.orderBestPatterns(const patterns : TArray); var zeroOneDistance, oneTwoDistance, zeroTwoDistance: Single; pointA, pointB, pointC, temp: IResultPoint; begin // Find distances between pattern centers zeroOneDistance := distance(patterns[0], patterns[1]); oneTwoDistance := distance(patterns[1], patterns[2]); zeroTwoDistance := distance(patterns[0], patterns[2]); // Assume one closest to other two is B; A and C will just be guesses at first if ((oneTwoDistance >= zeroOneDistance) and (oneTwoDistance >= zeroTwoDistance)) then begin pointB := patterns[0]; pointA := patterns[1]; pointC := patterns[2]; end else if ((zeroTwoDistance >= oneTwoDistance) and (zeroTwoDistance >= zeroOneDistance)) then begin pointB := patterns[1]; pointA := patterns[0]; pointC := patterns[2]; end else begin pointB := patterns[2]; pointA := patterns[0]; pointC := patterns[1]; end; // Use cross product to figure out whether A and C are correct or flipped. // This asks whether BC x BA has a positive z component, which is the arrangement // we want for A, B, C. If it's negative, then we've got it flipped around and // should swap A and C. if (crossProductZ(pointA, pointB, pointC) < 0) then begin temp := pointA; pointA := pointC; pointC := temp; end; patterns[0] := pointA; patterns[1] := pointB; patterns[2] := pointC; end; { TResultPointEventObject } constructor TResultPointEventObject.Create(const AEvent: TResultPointCallback); begin Self.FResultPointCallback := AEvent; end; end.