2007-03-08 04:03:40 +08:00
|
|
|
/******************************************************************************
|
2009-07-11 10:44:07 +08:00
|
|
|
** Filename: MergeNF.c
|
|
|
|
** Purpose: Program for merging similar nano-feature protos
|
|
|
|
** Author: Dan Johnson
|
|
|
|
** History: Wed Nov 21 09:55:23 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
**
|
2009-07-11 10:44:07 +08:00
|
|
|
** (c) Copyright Hewlett-Packard Company, 1988.
|
2007-03-08 04:03:40 +08:00
|
|
|
** 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.
|
|
|
|
******************************************************************************/
|
|
|
|
/**----------------------------------------------------------------------------
|
2009-07-11 10:44:07 +08:00
|
|
|
Include Files and Type Defines
|
2007-03-08 04:03:40 +08:00
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
#include "mergenf.h"
|
|
|
|
#include "general.h"
|
|
|
|
#include "efio.h"
|
|
|
|
#include "clusttool.h"
|
|
|
|
#include "cluster.h"
|
|
|
|
#include "oldlist.h"
|
|
|
|
#include "protos.h"
|
2009-07-11 10:44:07 +08:00
|
|
|
#include "ndminx.h"
|
2007-03-08 04:03:40 +08:00
|
|
|
#include "ocrfeatures.h"
|
|
|
|
#include "const.h"
|
|
|
|
#include "featdefs.h"
|
|
|
|
#include "intproto.h"
|
2009-07-11 10:44:07 +08:00
|
|
|
#include "varable.h"
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
|
|
/**----------------------------------------------------------------------------
|
2009-07-11 10:44:07 +08:00
|
|
|
Variables
|
2007-03-08 04:03:40 +08:00
|
|
|
-----------------------------------------------------------------------------**/
|
|
|
|
/*-------------------once in subfeat---------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
double_VAR(training_angle_match_scale, 1.0, "Angle Match Scale ...");
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
double_VAR(training_similarity_midpoint, 0.0075, "Similarity Midpoint ...");
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
double_VAR(training_similarity_curl, 2.0, "Similarity Curl ...");
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*-----------------------------once in fasttrain----------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
double_VAR(training_tangent_bbox_pad, 0.5, "Tangent bounding box pad ...");
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
double_VAR(training_orthogonal_bbox_pad, 2.5, "Orthogonal bounding box pad ...");
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
double_VAR(training_angle_pad, 45.0, "Angle pad ...");
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/**----------------------------------------------------------------------------
|
2009-07-11 10:44:07 +08:00
|
|
|
Global Data Definitions and Declarations
|
2007-03-08 04:03:40 +08:00
|
|
|
----------------------------------------------------------------------------**/
|
2009-07-11 10:44:07 +08:00
|
|
|
//int row_number; /* kludge due to linking problems */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/**----------------------------------------------------------------------------
|
2009-07-11 10:44:07 +08:00
|
|
|
Public Code
|
2007-03-08 04:03:40 +08:00
|
|
|
----------------------------------------------------------------------------**/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
FLOAT32 CompareProtos(PROTO p1, PROTO p2) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** p1, p2 protos to be compared
|
|
|
|
** Globals: none
|
|
|
|
** Operation: Compare protos p1 and p2 and return an estimate of the
|
|
|
|
** worst evidence rating that will result for any part of p1
|
|
|
|
** that is compared to p2. In other words, if p1 were broken
|
|
|
|
** into pico-features and each pico-feature was matched to p2,
|
|
|
|
** what is the worst evidence rating that will be achieved for
|
|
|
|
** any pico-feature.
|
|
|
|
** Return: Worst possible result when matching p1 to p2.
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Mon Nov 26 08:27:53 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
2009-07-11 10:44:07 +08:00
|
|
|
FEATURE Feature;
|
|
|
|
FLOAT32 WorstEvidence = WORST_EVIDENCE;
|
|
|
|
FLOAT32 Evidence;
|
|
|
|
FLOAT32 Angle, Length;
|
|
|
|
|
|
|
|
/* if p1 and p2 are not close in length, don't let them match */
|
|
|
|
Length = fabs (p1->Length - p2->Length);
|
|
|
|
if (Length > MAX_LENGTH_MISMATCH)
|
|
|
|
return (0.0);
|
|
|
|
|
|
|
|
/* create a dummy pico-feature to be used for comparisons */
|
|
|
|
Feature = NewFeature (&PicoFeatDesc);
|
|
|
|
Feature->Params[PicoFeatDir] = p1->Angle;
|
|
|
|
|
|
|
|
/* convert angle to radians */
|
|
|
|
Angle = p1->Angle * 2.0 * PI;
|
|
|
|
|
|
|
|
/* find distance from center of p1 to 1/2 picofeat from end */
|
|
|
|
Length = p1->Length / 2.0 - GetPicoFeatureLength () / 2.0;
|
|
|
|
if (Length < 0) Length = 0;
|
|
|
|
|
|
|
|
/* set the dummy pico-feature at one end of p1 and match it to p2 */
|
|
|
|
Feature->Params[PicoFeatX] = p1->X + cos (Angle) * Length;
|
|
|
|
Feature->Params[PicoFeatY] = p1->Y + sin (Angle) * Length;
|
|
|
|
if (DummyFastMatch (Feature, p2)) {
|
|
|
|
Evidence = SubfeatureEvidence (Feature, p2);
|
|
|
|
if (Evidence < WorstEvidence)
|
|
|
|
WorstEvidence = Evidence;
|
|
|
|
} else {
|
|
|
|
FreeFeature(Feature);
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the dummy pico-feature at the other end of p1 and match it to p2 */
|
|
|
|
Feature->Params[PicoFeatX] = p1->X - cos (Angle) * Length;
|
|
|
|
Feature->Params[PicoFeatY] = p1->Y - sin (Angle) * Length;
|
|
|
|
if (DummyFastMatch (Feature, p2)) {
|
|
|
|
Evidence = SubfeatureEvidence (Feature, p2);
|
|
|
|
if (Evidence < WorstEvidence)
|
|
|
|
WorstEvidence = Evidence;
|
|
|
|
} else {
|
|
|
|
FreeFeature(Feature);
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeFeature (Feature);
|
|
|
|
return (WorstEvidence);
|
|
|
|
|
|
|
|
} /* CompareProtos */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
void ComputeMergedProto (
|
2009-07-11 10:44:07 +08:00
|
|
|
PROTO p1,
|
|
|
|
PROTO p2,
|
|
|
|
FLOAT32 w1,
|
|
|
|
FLOAT32 w2,
|
|
|
|
PROTO MergedProto)
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** p1, p2 protos to be merged
|
|
|
|
** w1, w2 weight of each proto
|
|
|
|
** MergedProto place to put resulting merged proto
|
|
|
|
** Globals: none
|
|
|
|
** Operation: This routine computes a proto which is the weighted
|
|
|
|
** average of protos p1 and p2. The new proto is returned
|
|
|
|
** in MergedProto.
|
|
|
|
** Return: none (results are returned in MergedProto)
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Mon Nov 26 08:15:08 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
2009-07-11 10:44:07 +08:00
|
|
|
FLOAT32 TotalWeight;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
TotalWeight = w1 + w2;
|
|
|
|
w1 /= TotalWeight;
|
|
|
|
w2 /= TotalWeight;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
MergedProto->X = p1->X * w1 + p2->X * w2;
|
|
|
|
MergedProto->Y = p1->Y * w1 + p2->Y * w2;
|
|
|
|
MergedProto->Length = p1->Length * w1 + p2->Length * w2;
|
|
|
|
MergedProto->Angle = p1->Angle * w1 + p2->Angle * w2;
|
|
|
|
FillABC(MergedProto);
|
|
|
|
} /* ComputeMergedProto */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
int FindClosestExistingProto(CLASS_TYPE Class, int NumMerged[],
|
|
|
|
PROTOTYPE *Prototype) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** Class class to search for matching old proto in
|
|
|
|
** NumMerged[] # of protos merged into each proto of Class
|
|
|
|
** Prototype new proto to find match for
|
|
|
|
** Globals: none
|
|
|
|
** Operation: This routine searches thru all of the prototypes in
|
|
|
|
** Class and returns the id of the proto which would provide
|
|
|
|
** the best approximation of Prototype. If no close
|
|
|
|
** approximation can be found, NO_PROTO is returned.
|
|
|
|
** Return: Id of closest proto in Class or NO_PROTO.
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Sat Nov 24 11:42:58 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
2009-07-11 10:44:07 +08:00
|
|
|
PROTO_STRUCT NewProto;
|
|
|
|
PROTO_STRUCT MergedProto;
|
|
|
|
int Pid;
|
|
|
|
PROTO Proto;
|
|
|
|
int BestProto;
|
|
|
|
FLOAT32 BestMatch;
|
|
|
|
FLOAT32 Match, OldMatch, NewMatch;
|
|
|
|
|
|
|
|
MakeNewFromOld (&NewProto, Prototype);
|
|
|
|
|
|
|
|
BestProto = NO_PROTO;
|
|
|
|
BestMatch = WORST_MATCH_ALLOWED;
|
|
|
|
for (Pid = 0; Pid < Class->NumProtos; Pid++) {
|
|
|
|
Proto = ProtoIn(Class, Pid);
|
|
|
|
ComputeMergedProto(Proto, &NewProto,
|
|
|
|
(FLOAT32) NumMerged[Pid], 1.0, &MergedProto);
|
|
|
|
OldMatch = CompareProtos(Proto, &MergedProto);
|
|
|
|
NewMatch = CompareProtos(&NewProto, &MergedProto);
|
|
|
|
Match = MIN(OldMatch, NewMatch);
|
|
|
|
if (Match > BestMatch) {
|
|
|
|
BestProto = Pid;
|
|
|
|
BestMatch = Match;
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
2009-07-11 10:44:07 +08:00
|
|
|
}
|
|
|
|
return BestProto;
|
|
|
|
} /* FindClosestExistingProto */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
void MakeNewFromOld(PROTO New, PROTOTYPE *Old) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** New new proto to be filled in
|
|
|
|
** Old old proto to be converted
|
|
|
|
** Globals: none
|
|
|
|
** Operation: This fills in the fields of the New proto based on the
|
|
|
|
** fields of the Old proto.
|
|
|
|
** Return: none
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Mon Nov 26 09:45:39 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
2009-07-11 10:44:07 +08:00
|
|
|
New->X = CenterX(Old->Mean);
|
|
|
|
New->Y = CenterY(Old->Mean);
|
|
|
|
New->Length = LengthOf(Old->Mean);
|
|
|
|
New->Angle = OrientationOf(Old->Mean);
|
|
|
|
FillABC(New);
|
|
|
|
} /* MakeNewFromOld */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*-------------------once in subfeat---------------------------------*/
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* SubfeatureEvidence
|
|
|
|
*
|
|
|
|
* Compare a feature to a prototype. Print the result.
|
|
|
|
**********************************************************************/
|
2009-07-11 10:44:07 +08:00
|
|
|
FLOAT32 SubfeatureEvidence(FEATURE Feature, PROTO Proto) {
|
|
|
|
float Distance;
|
|
|
|
float Dangle;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
Dangle = Proto->Angle - Feature->Params[PicoFeatDir];
|
|
|
|
if (Dangle < -0.5) Dangle += 1.0;
|
|
|
|
if (Dangle > 0.5) Dangle -= 1.0;
|
|
|
|
Dangle *= training_angle_match_scale;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
Distance = Proto->A * Feature->Params[PicoFeatX] +
|
|
|
|
Proto->B * Feature->Params[PicoFeatY] +
|
|
|
|
Proto->C;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
return (EvidenceOf (Distance * Distance + Dangle * Dangle));
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* EvidenceOf
|
|
|
|
*
|
|
|
|
* Return the new type of evidence number corresponding to this
|
|
|
|
* distance value. This number is no longer based on the chi squared
|
|
|
|
* approximation. The equation that represents the transform is:
|
|
|
|
* 1 / (1 + (sim / midpoint) ^ curl)
|
|
|
|
**********************************************************************/
|
|
|
|
FLOAT32 EvidenceOf (
|
|
|
|
register FLOAT32 Similarity)
|
|
|
|
{
|
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
Similarity /= training_similarity_midpoint;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
if (training_similarity_curl == 3)
|
|
|
|
Similarity = Similarity * Similarity * Similarity;
|
|
|
|
else if (training_similarity_curl == 2)
|
|
|
|
Similarity = Similarity * Similarity;
|
|
|
|
else
|
|
|
|
Similarity = static_cast<float>(pow(static_cast<double>(Similarity),
|
|
|
|
training_similarity_curl));
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
return (1.0 / (1.0 + Similarity));
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
BOOL8 DummyFastMatch (
|
2009-07-11 10:44:07 +08:00
|
|
|
FEATURE Feature,
|
|
|
|
PROTO Proto)
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** Feature feature to be "fast matched" to proto
|
|
|
|
** Proto proto being "fast matched" against
|
|
|
|
** Globals:
|
|
|
|
** training_tangent_bbox_pad bounding box pad tangent to proto
|
|
|
|
** training_orthogonal_bbox_pad bounding box pad orthogonal to proto
|
|
|
|
** Operation: This routine returns TRUE if Feature would be matched
|
|
|
|
** by a fast match table built from Proto.
|
|
|
|
** Return: TRUE if feature could match Proto.
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Wed Nov 14 17:19:58 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
2009-07-11 10:44:07 +08:00
|
|
|
FRECT BoundingBox;
|
|
|
|
FLOAT32 MaxAngleError;
|
|
|
|
FLOAT32 AngleError;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
MaxAngleError = training_angle_pad / 360.0;
|
|
|
|
AngleError = fabs (Proto->Angle - Feature->Params[PicoFeatDir]);
|
|
|
|
if (AngleError > 0.5)
|
|
|
|
AngleError = 1.0 - AngleError;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
if (AngleError > MaxAngleError)
|
|
|
|
return (FALSE);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
ComputePaddedBoundingBox (Proto,
|
|
|
|
training_tangent_bbox_pad * GetPicoFeatureLength (),
|
|
|
|
training_orthogonal_bbox_pad * GetPicoFeatureLength (),
|
|
|
|
&BoundingBox);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
return PointInside(&BoundingBox, Feature->Params[PicoFeatX],
|
|
|
|
Feature->Params[PicoFeatY]);
|
|
|
|
} /* DummyFastMatch */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
void ComputePaddedBoundingBox (PROTO Proto, FLOAT32 TangentPad,
|
|
|
|
FLOAT32 OrthogonalPad, FRECT *BoundingBox) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** Proto proto to compute bounding box for
|
|
|
|
** TangentPad amount of pad to add in direction of segment
|
|
|
|
** OrthogonalPad amount of pad to add orthogonal to segment
|
|
|
|
** BoundingBox place to put results
|
|
|
|
** Globals: none
|
|
|
|
** Operation: This routine computes a bounding box that encloses the
|
|
|
|
** specified proto along with some padding. The
|
|
|
|
** amount of padding is specified as separate distances
|
|
|
|
** in the tangential and orthogonal directions.
|
|
|
|
** Return: none (results are returned in BoundingBox)
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Wed Nov 14 14:55:30 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
2009-07-11 10:44:07 +08:00
|
|
|
FLOAT32 Pad, Length, Angle;
|
|
|
|
FLOAT32 CosOfAngle, SinOfAngle;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
Length = Proto->Length / 2.0 + TangentPad;
|
|
|
|
Angle = Proto->Angle * 2.0 * PI;
|
|
|
|
CosOfAngle = fabs(cos(Angle));
|
|
|
|
SinOfAngle = fabs(sin(Angle));
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
Pad = MAX (CosOfAngle * Length, SinOfAngle * OrthogonalPad);
|
|
|
|
BoundingBox->MinX = Proto->X - Pad;
|
|
|
|
BoundingBox->MaxX = Proto->X + Pad;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
Pad = MAX(SinOfAngle * Length, CosOfAngle * OrthogonalPad);
|
|
|
|
BoundingBox->MinY = Proto->Y - Pad;
|
|
|
|
BoundingBox->MaxY = Proto->Y + Pad;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
} /* ComputePaddedBoundingBox */
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
2009-07-11 10:44:07 +08:00
|
|
|
BOOL8 PointInside(FRECT *Rectangle, FLOAT32 X, FLOAT32 Y) {
|
2007-03-08 04:03:40 +08:00
|
|
|
/*
|
2009-07-11 10:44:07 +08:00
|
|
|
** Parameters:
|
|
|
|
** Globals: none
|
|
|
|
** Operation: Return TRUE if point (X,Y) is inside of Rectangle.
|
|
|
|
** Return: Return TRUE if point (X,Y) is inside of Rectangle.
|
|
|
|
** Exceptions: none
|
|
|
|
** History: Wed Nov 14 17:26:35 1990, DSJ, Created.
|
2007-03-08 04:03:40 +08:00
|
|
|
*/
|
2009-07-11 10:44:07 +08:00
|
|
|
if (X < Rectangle->MinX) return (FALSE);
|
|
|
|
if (X > Rectangle->MaxX) return (FALSE);
|
|
|
|
if (Y < Rectangle->MinY) return (FALSE);
|
|
|
|
if (Y > Rectangle->MaxY) return (FALSE);
|
|
|
|
return (TRUE);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2009-07-11 10:44:07 +08:00
|
|
|
} /* PointInside */
|