Circle to polygon conversion: a few enhancements:
* Remove duplicate code * fix incorrect formulas is some places * add comments
This commit is contained in:
parent
9c62792245
commit
51fe063524
|
@ -350,6 +350,7 @@ set( COMMON_SRCS
|
|||
tool/zoom_tool.cpp
|
||||
|
||||
geometry/convex_hull.cpp
|
||||
geometry/geometry_utils.cpp
|
||||
geometry/seg.cpp
|
||||
geometry/shape.cpp
|
||||
geometry/shape_collisions.cpp
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file geometry_utils.cpp
|
||||
* @brief a few functions useful in geometry calculations.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <common.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
|
||||
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree )
|
||||
{
|
||||
// calculate the number of segments to approximate a circle by segments
|
||||
// given the max distance between the middle of a segment and the circle
|
||||
|
||||
// error relative to the radius value:
|
||||
double rel_error = (double)aErrorMax / aRadius;
|
||||
// minimal arc increment in degrees:
|
||||
double step = 180 / M_PI * acos( 1.0 - rel_error ) * 2;
|
||||
// the minimal seg count for a arc
|
||||
int segCount = KiROUND( fabs( aArcAngleDegree ) / step );
|
||||
|
||||
// Ensure at least one segment is used
|
||||
return std::max( segCount, 1 );
|
||||
}
|
||||
|
||||
|
||||
double GetCircletoPolyCorrectionFactor( int aSegCountforCircle )
|
||||
{
|
||||
/* calculates the coeff to compensate radius reduction of circle
|
||||
* due to the segment approx.
|
||||
* For a circle the min radius is radius * cos( 2PI / aSegCountforCircle / 2)
|
||||
* this is the distance between the center and the middle of the segment.
|
||||
* therfore, to move the middle of the segment to the circle (distance = radius)
|
||||
* the correctionFactor is 1 /cos( PI/aSegCountforCircle )
|
||||
*/
|
||||
double correctionFactor = 1.0 / cos( M_PI / aSegCountforCircle );
|
||||
|
||||
return correctionFactor;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file geometry_utils.h
|
||||
* @brief a few functions useful in geometry calculations.
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_UTILS_H
|
||||
#define GEOMETRY_UTILS_H
|
||||
|
||||
/**
|
||||
* @return the number of segments to approximate a arc by segments
|
||||
* with a given max error (this number is >= 1)
|
||||
* @param aRadius is the radius od the circle or arc
|
||||
* @param aErrorMax is the max error
|
||||
* This is the max distance between the middle of a segment and the circle.
|
||||
* @param aArcAngleDegree is the arc angle in degrees
|
||||
*/
|
||||
int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree );
|
||||
|
||||
/**
|
||||
* @return the correction factor to approximate a circle by segùments
|
||||
* @param aSegCountforCircle is the number of segments to approximate the circle
|
||||
*
|
||||
* When creating a polygon from a circle, the polygon is inside the circle.
|
||||
* Only corners are on the circle.
|
||||
* This is incorrect when building clearance areas of circles, that need to build
|
||||
* the equivalent polygon outside the circle
|
||||
* The correction factor is a scaling factor to apply to the radius to build a
|
||||
* polygon outside the circle (only the middle of each segment is on the circle
|
||||
*/
|
||||
double GetCircletoPolyCorrectionFactor( int aSegCountforCircle );
|
||||
|
||||
|
||||
#endif // #ifndef GEOMETRY_UTILS_H
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2009-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -47,6 +47,7 @@
|
|||
#include <class_module.h>
|
||||
#include <class_edge_mod.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
// These variables are parameters used in addTextSegmToPoly.
|
||||
// But addTextSegmToPoly is a call-back function,
|
||||
|
@ -55,6 +56,11 @@ static int s_textWidth;
|
|||
static int s_textCircle2SegmentCount;
|
||||
static SHAPE_POLY_SET* s_cornerBuffer;
|
||||
|
||||
// The max error is the distance between the middle of a segment, and the circle
|
||||
// for circle/arc to segment approximation.
|
||||
// Warning: too small values can create very long calculation time in zone filling
|
||||
double s_error_max = Millimeter2iu( 0.01 );
|
||||
|
||||
// This is a call back function, used by DrawGraphicText to draw the 3D text shape:
|
||||
static void addTextSegmToPoly( int x0, int y0, int xf, int yf )
|
||||
{
|
||||
|
@ -68,7 +74,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_
|
|||
{
|
||||
// Number of segments to convert a circle to a polygon
|
||||
const int segcountforcircle = 18;
|
||||
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
|
||||
double correctionFactor = GetCircletoPolyCorrectionFactor( segcountforcircle );
|
||||
|
||||
// convert tracks and vias:
|
||||
for( TRACK* track = m_Track; track != NULL; track = track->Next() )
|
||||
|
@ -504,25 +510,12 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerB
|
|||
|
||||
if( m_Shape == S_CIRCLE || m_Shape == S_ARC )
|
||||
{
|
||||
// this is an ugly hack, but I don't want to change the file format now that we are in feature freeze.
|
||||
// the circle to segment count parameter is essentially useless for larger circle/arc shapes as
|
||||
// it doesn't provide sufficient approximation accuracy.
|
||||
// Here we compute the necessary number of segments based on error between circle and segments
|
||||
// The max error is the distance between the middle of a segment, and the circle
|
||||
//
|
||||
// Warning: too small values can create very long calculation time in zone filling
|
||||
double error_max = Millimeter2iu( 0.05 );
|
||||
// error relative to the radius value
|
||||
double rel_error = error_max / GetRadius();
|
||||
// best arc increment
|
||||
double step = 180 / M_PI * acos( 1.0 - rel_error );
|
||||
// the best seg count for a circle
|
||||
int segCount = KiROUND( 360.0 / step );
|
||||
int segCount = GetArcToSegmentCount( GetRadius(), s_error_max, 360.0 );
|
||||
|
||||
if( segCount > aCircleToSegmentsCount )
|
||||
{
|
||||
aCircleToSegmentsCount = segCount;
|
||||
aCorrectionFactor = 1.0 / cos( M_PI / (aCircleToSegmentsCount * 2) );
|
||||
aCorrectionFactor = GetCircletoPolyCorrectionFactor( aCircleToSegmentsCount );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <class_drawsegment.h>
|
||||
#include <base_units.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
|
||||
/**
|
||||
|
@ -167,16 +168,11 @@ static DRAWSEGMENT* findPoint( const wxPoint& aPoint, std::vector< DRAWSEGMENT*
|
|||
}
|
||||
|
||||
|
||||
// Error max when converting a circle or arc to segments.
|
||||
// Avoid too small values that create a very long calculation time
|
||||
// in zone fillings
|
||||
#define ARC_ACCURACY ( 0.05 * IU_PER_MM )
|
||||
|
||||
int calcArcSteps( int aRadius, int aSweptAngle )
|
||||
{
|
||||
int circleSteps = M_PI / acos( ( aRadius - ARC_ACCURACY ) / aRadius );
|
||||
int arcSteps = circleSteps * fabs( aSweptAngle ) / 3600.0;
|
||||
|
||||
return std::max( arcSteps, 1 );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function ConvertOutlineToPolygon
|
||||
|
@ -238,7 +234,8 @@ bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
|
|||
wxPoint pstart = graphic->GetArcStart();
|
||||
wxPoint center = graphic->GetCenter();
|
||||
double angle = -graphic->GetAngle();
|
||||
int steps = calcArcSteps( graphic->GetRadius(), angle );
|
||||
int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_ACCURACY,
|
||||
(double)angle / 10.0 );
|
||||
wxPoint pt;
|
||||
|
||||
for( int step = 1; step<=steps; ++step )
|
||||
|
@ -296,9 +293,8 @@ bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
|
|||
// Output the Edge.Cuts perimeter as circle or polygon.
|
||||
if( graphic->GetShape() == S_CIRCLE )
|
||||
{
|
||||
TransformCircleToPolygon( aPolygons, graphic->GetCenter(),
|
||||
graphic->GetRadius(),
|
||||
calcArcSteps( graphic->GetRadius(), 3600 ) );
|
||||
int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_ACCURACY, 360.0 );
|
||||
TransformCircleToPolygon( aPolygons, graphic->GetCenter(), graphic->GetRadius(), steps );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -344,7 +340,8 @@ bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
|
|||
wxPoint pend = graphic->GetArcEnd();
|
||||
wxPoint pcenter = graphic->GetCenter();
|
||||
double angle = -graphic->GetAngle();
|
||||
int steps = calcArcSteps( graphic->GetRadius(), angle );
|
||||
int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_ACCURACY,
|
||||
(double)angle / 10.0 );
|
||||
|
||||
if( !close_enough( prevPt, pstart, prox ) )
|
||||
{
|
||||
|
@ -436,7 +433,7 @@ bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
|
|||
double angle = 3600.0;
|
||||
wxPoint start = center;
|
||||
int radius = graphic->GetRadius();
|
||||
int steps = calcArcSteps( radius, angle );
|
||||
int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_ACCURACY, 360.0 );
|
||||
wxPoint nextPt;
|
||||
|
||||
start.x += radius;
|
||||
|
@ -494,7 +491,8 @@ bool ConvertOutlineToPolygon( std::vector< DRAWSEGMENT* >& aSegList,
|
|||
wxPoint pend = graphic->GetArcEnd();
|
||||
wxPoint pcenter = graphic->GetCenter();
|
||||
double angle = -graphic->GetAngle();
|
||||
int steps = calcArcSteps( graphic->GetRadius(), angle );
|
||||
int steps = GetArcToSegmentCount( graphic->GetRadius(), ARC_ACCURACY,
|
||||
(double)angle / 10.0 );
|
||||
|
||||
if( !close_enough( prevPt, pstart, prox ) )
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
#include <convert_basic_shapes_to_polygon.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
#include "specctra.h"
|
||||
|
||||
|
@ -765,11 +766,13 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
|
|||
|
||||
double radius = GetLineLength( graphic->GetStart(), graphic->GetEnd() );
|
||||
|
||||
const int SEG_PER_CIRCLE = 36; // seg count to approximate circle by line segments
|
||||
// seg count to approximate circle by line segments
|
||||
int err_max = Millimeter2iu( 0.05 );
|
||||
int seg_per_circle = GetArcToSegmentCount( radius, err_max, 360.0 );
|
||||
|
||||
for( int ii = 0; ii < SEG_PER_CIRCLE; ++ii )
|
||||
for( int ii = 0; ii < seg_per_circle; ++ii )
|
||||
{
|
||||
double radians = 2*M_PI / SEG_PER_CIRCLE * ii;
|
||||
double radians = 2*M_PI / seg_per_circle * ii;
|
||||
wxPoint point( KiROUND( radius * cos( radians ) ),
|
||||
KiROUND( radius * sin( radians ) ) );
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <geometry/shape_poly_set.h>
|
||||
#include <geometry/shape_file_io.h>
|
||||
#include <geometry/convex_hull.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
#include "zone_filler.h"
|
||||
|
||||
|
@ -299,10 +300,10 @@ void ZONE_FILLER::buildZoneFeatureHoleList( const ZONE_CONTAINER* aZone,
|
|||
|
||||
/* calculates the coeff to compensate radius reduction of holes clearance
|
||||
* due to the segment approx.
|
||||
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
|
||||
* correctionFactor is 1 /cos( PI/s_CircleToSegmentsCount )
|
||||
* For a circle the min radius is radius * cos( 2PI / segsPerCircle / 2)
|
||||
* correctionFactor is 1 /cos( PI/segsPerCircle )
|
||||
*/
|
||||
correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
|
||||
correctionFactor = GetCircletoPolyCorrectionFactor( segsPerCircle );
|
||||
|
||||
aFeatures.RemoveAllContours();
|
||||
|
||||
|
@ -683,11 +684,8 @@ void ZONE_FILLER::computeRawFilledAreas( const ZONE_CONTAINER* aZone,
|
|||
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
|
||||
|
||||
/* calculates the coeff to compensate radius reduction of holes clearance
|
||||
* due to the segment approx.
|
||||
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
|
||||
* s_Correction is 1 /cos( PI/s_CircleToSegmentsCount )
|
||||
*/
|
||||
correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
|
||||
correctionFactor = GetCircletoPolyCorrectionFactor( segsPerCircle );
|
||||
|
||||
if( s_DumpZonesWhenFilling )
|
||||
dumper->BeginGroup( "clipper-zone" );
|
||||
|
|
Loading…
Reference in New Issue