kicad/qa/pns/playground.cpp

370 lines
9.9 KiB
C++
Raw Normal View History

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers.
*
* 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
*/
// WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality
// (unless you want to improve it).
#include <pgm_base.h>
#include <qa_utils/utility_registry.h>
#include "pns_log_viewer_frame.h"
#include "label_manager.h"
2021-06-09 13:32:18 +00:00
#include <geometry/shape_arc.h>
2021-06-09 21:28:29 +00:00
std::shared_ptr<PNS_LOG_VIEWER_OVERLAY> overlay;
2021-06-09 13:32:18 +00:00
template<class T>
2021-06-09 21:39:01 +00:00
static T within_range(T x, T minval, T maxval, T wrap)
2021-06-09 13:32:18 +00:00
{
int rv;
while (maxval >= wrap)
maxval -= wrap;
while (maxval < 0)
maxval += wrap;
while (minval >= wrap)
minval -= wrap;
while (minval < 0)
minval += wrap;
while (x < 0)
x += wrap;
while (x >= wrap)
x -= wrap;
if (maxval > minval)
rv = (x >= minval && x <= maxval) ? 1 : 0;
else
rv = (x >= minval || x <= maxval) ? 1 : 0;
return rv;
}
2021-06-09 21:39:01 +00:00
static bool sliceContainsPoint( SHAPE_ARC a, VECTOR2D p )
2021-06-09 13:32:18 +00:00
{
2021-06-09 21:28:29 +00:00
double phi = 180.0 / M_PI * atan2( p.y - a.GetCenter().y, p.x - a.GetCenter().x );
double ca = a.GetCentralAngle();
double sa = a.GetStartAngle();
double ea;
if( ca >= 0 )
{
ea = sa + ca;
}
else
{
ea = sa;
sa += ca;
}
return within_range( phi, sa, ea, 360.0 );
2021-06-09 13:32:18 +00:00
}
2021-06-09 21:39:01 +00:00
static int arclineIntersect( const SHAPE_ARC& a, const SEG& s, VECTOR2D* pts )
2021-06-09 21:28:29 +00:00
{
VECTOR2I c = a.GetCenter();
double r = a.GetRadius();
VECTOR2I nearest = s.LineProject( c );
double nd = (c - nearest).EuclideanNorm();
/*overlay->SetStrokeColor( RED );
overlay->AnnotatedPoint( s.A, 200000 );
overlay->SetStrokeColor( GREEN );
overlay->AnnotatedPoint( s.B, 200000 );
overlay->SetStrokeColor( YELLOW );
overlay->AnnotatedPoint( c, 200000 );
overlay->SetStrokeColor( WHITE );
overlay->Arc( a );
overlay->SetStrokeColor( DARKGRAY );
overlay->Circle( a.GetCenter(), a.GetRadius() );*/
if( nd > r )
return 0;
double ll = r * r - nd * nd;
double l = 0;
if( ll > 0 )
l = sqrt(ll);
int n = 0;
VECTOR2I perp = ( s.B - s.A ).Resize( l );
VECTOR2I p0( nearest + perp );
VECTOR2I p1( nearest - perp );
if( sliceContainsPoint( a, p0 ) ) { pts[n] = p0; n++; }
if( sliceContainsPoint( a, p1 ) ) { pts[n] = p1; n++; }
//for(int i = 0; i < n ; i++) overlay->AnnotatedPoint( pts[i], 40000 );
return n;
}
2021-06-09 21:39:01 +00:00
int intersectArc2Arc( const SHAPE_ARC& a1, const SHAPE_ARC& a2, VECTOR2D* ips )
2021-06-09 21:28:29 +00:00
{
VECTOR2I dc( a2.GetCenter() - a1.GetCenter() );
double dcl = dc.EuclideanNorm();
double r1 = a1.GetRadius();
double r2 = a2.GetRadius();
if( dc.x == 0 && dc.y == 0 )
{
if(r1 == r2)
{
ips[0] = a1.GetP0();
return 1;
}
}
double d = ( dcl * dcl - r2*r2 + r1*r1 ) / (2 * dcl);
//overlay->SetStrokeColor( DARKGRAY );
//overlay->Circle( a1.GetCenter(), a1.GetRadius() );
//overlay->SetStrokeColor( DARKGRAY );
//overlay->Circle( a2.GetCenter(), a2.GetRadius() );
double r1sq = r1 * r1;
double dsq = d * d;
if( r1sq < dsq )
return 0;
double q = sqrt ( r1sq - dsq );
// printf("d %.1f q %.1f dcl %.1f\n", d, q, dcl );
VECTOR2D pp = a1.GetCenter() + dc.Resize( d );
VECTOR2D ip0 = pp + dc.Perpendicular().Resize(q);
VECTOR2D ip1 = pp - dc.Perpendicular().Resize(q);
int n_ips = 0;
if( sliceContainsPoint( a1, ip0 ) )
ips[n_ips++] = ip0;
if( sliceContainsPoint( a1, ip1 ) )
ips[n_ips++] = ip1;
return n_ips;
}
2021-06-09 21:39:01 +00:00
bool collideArc2Arc( const SHAPE_ARC& a1, const SHAPE_ARC& a2, int clearance, SEG& minDistSeg )
2021-06-09 13:32:18 +00:00
{
2021-06-09 21:39:01 +00:00
SEG mediatrix( a1.GetCenter(), a2.GetCenter() );
2021-06-09 13:32:18 +00:00
2021-06-09 21:39:01 +00:00
int nA = 0, nB = 0;
2021-06-09 21:28:29 +00:00
VECTOR2D ptsA[8];
VECTOR2D ptsB[8];
2021-06-09 13:32:18 +00:00
2021-06-09 21:28:29 +00:00
VECTOR2D ips[4];
2021-06-09 21:39:01 +00:00
if( intersectArc2Arc( a1, a2, ips ) > 0 )
2021-06-09 13:32:18 +00:00
{
2021-06-09 21:28:29 +00:00
minDistSeg.A = minDistSeg.B = ips[0];
return true;
2021-06-09 13:32:18 +00:00
}
2021-06-09 21:39:01 +00:00
bool cocentered = ( mediatrix.A == mediatrix.B );
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
// arcs don't have the same center point
if( !cocentered )
{
nA = arclineIntersect( a1, mediatrix, ptsA );
nB = arclineIntersect( a2, mediatrix, ptsB );
}
/*overlay->SetStrokeColor( LIGHTRED );
2021-06-09 21:28:29 +00:00
overlay->Line( SEG( a2.GetP0(), a2.GetCenter() ) );
2021-06-09 21:39:01 +00:00
overlay->Line( SEG( a2.GetP1(), a2.GetCenter() ) );*/
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
nA += arclineIntersect( a1, SEG( a2.GetP0(), a2.GetCenter() ), ptsA + nA );
nA += arclineIntersect( a1, SEG( a2.GetP1(), a2.GetCenter() ), ptsA + nA );
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
/*overlay->SetStrokeColor( LIGHTBLUE );
2021-06-09 21:28:29 +00:00
overlay->Line( SEG( a1.GetP0(), a1.GetCenter() ) );
2021-06-09 21:39:01 +00:00
overlay->Line( SEG( a1.GetP1(), a1.GetCenter() ) );*/
nB += arclineIntersect( a2, SEG( a1.GetP0(), a1.GetCenter() ), ptsB + nB );
nB += arclineIntersect( a2, SEG( a1.GetP1(), a1.GetCenter() ), ptsB + nB );
2021-06-09 21:28:29 +00:00
2021-06-09 13:32:18 +00:00
ptsA[nA++] = a1.GetP0();
ptsA[nA++] = a1.GetP1();
ptsB[nB++] = a2.GetP0();
ptsB[nB++] = a2.GetP1();
2021-06-09 21:39:01 +00:00
// printf("nA %d nB %d\n", nA, nB );
2021-06-09 13:32:18 +00:00
double minDist;
2021-06-09 21:39:01 +00:00
bool minDistFound = false;
2021-06-09 13:32:18 +00:00
for( int i = 0; i < nA; i++ )
for( int j = 0; j < nB; j++ )
{
2021-06-09 21:39:01 +00:00
double dist =
( ptsA[i] - ptsB[j] ).EuclideanNorm() - a1.GetWidth() / 2 - a2.GetWidth() / 2;
2021-06-09 13:32:18 +00:00
2021-06-09 21:39:01 +00:00
/* overlay->SetStrokeColor( RED );
2021-06-09 21:28:29 +00:00
overlay->AnnotatedPoint( ptsA[i], 100000 );
overlay->SetStrokeColor( GREEN );
overlay->AnnotatedPoint( ptsB[j], 100000 );*/
//printf("dist %.1f\n", dist );
2021-06-09 13:32:18 +00:00
if( dist < clearance )
{
2021-06-09 21:39:01 +00:00
if( !minDistFound || dist < minDist )
2021-06-09 13:32:18 +00:00
{
2021-06-09 21:28:29 +00:00
minDist = dist;
2021-06-09 13:32:18 +00:00
minDistSeg = SEG( ptsA[i], ptsB[j] );
}
minDistFound = true;
}
}
return minDistFound;
}
int playground_main_func( int argc, char* argv[] )
{
auto frame = new PNS_LOG_VIEWER_FRAME( nullptr );
Pgm().App().SetTopWindow( frame ); // wxApp gets a face.
frame->Show();
2021-06-09 21:39:01 +00:00
struct ARC_DATA
{
double sx, sy, ex, ey, ca, w;
};
const ARC_DATA test_data [] =
{
{73.843527, 74.355869, 71.713528, 72.965869, -76.36664803, 0.2},
{71.236473, 74.704131, 73.366472, 76.094131, -76.36664803, 0.2},
{82.542335, 74.825975, 80.413528, 73.435869, -76.4, 0.2},
{76.491192, 73.839894, 78.619999, 75.23, -76.4, 0.2},
{94.665667, 73.772941, 96.446472, 74.934131, -267.9, 0.2},
{94.750009, 73.74012, 93.6551, 73.025482, -255.5, 0.2},
{89.318807, 74.810106, 87.19, 73.42, -76.4, 0.2},
{87.045667, 74.632941, 88.826472, 75.794131, -267.9, 0.2},
{79.279991, 80.67988, 80.3749, 81.394518, -255.5, 0.2},
{79.279991, 80.688898, 80.3749, 81.403536, -255.5, 0.2},
{72.87525, 80.173054, 73.970159, 80.887692, -255.5, 0.2},
{73.063537, 82.295989, 71.968628, 81.581351, -255.5, 0.2},
{88.495265, 81.766089, 90.090174, 82.867869, -255.5, 0.2},
{86.995265, 81.387966, 89.090174, 82.876887, -255.5, 0.2},
{96.149734, 81.792126, 94.99, 83.37, -347.2, 0.2},
{94.857156, 81.240589, 95.91, 83.9, -288.5, 0.2}
};
2021-06-09 21:28:29 +00:00
overlay = frame->GetOverlay();
overlay->SetIsFill(false);
overlay->SetLineWidth(10000);
2021-06-09 21:28:29 +00:00
std::vector<SHAPE_ARC> arcs;
2021-06-09 21:39:01 +00:00
int n_arcs = sizeof( test_data ) / sizeof( ARC_DATA );
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
BOX2I vp;
2021-06-09 21:39:01 +00:00
for( int i = 0; i < n_arcs; i++ )
2021-06-09 21:28:29 +00:00
{
2021-06-09 21:39:01 +00:00
const ARC_DATA& d = test_data[i];
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
SHAPE_ARC arc( VECTOR2D( Millimeter2iu( d.sx ), Millimeter2iu( d.sy ) ),
VECTOR2D( Millimeter2iu( d.ex ), Millimeter2iu( d.ey ) ), d.ca, d.w );
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
arcs.push_back( arc );
2021-06-09 21:28:29 +00:00
2021-06-09 21:39:01 +00:00
if( i == 0 )
vp = arc.BBox();
else
vp.Merge( arc.BBox() );
2021-06-09 21:28:29 +00:00
}
2021-06-09 21:39:01 +00:00
printf("Read %lu arcs\n", arcs.size() );
2021-06-09 21:28:29 +00:00
LABEL_MANAGER labelMgr( frame->GetPanel()->GetGAL() );
2021-06-09 21:39:01 +00:00
frame->GetPanel()->GetView()->SetViewport( BOX2D( vp.GetOrigin(), vp.GetSize() ) );
overlay->SetStrokeColor( WHITE );
overlay->SetLineWidth( 10000.0 );
2021-06-09 21:28:29 +00:00
overlay->SetStrokeColor( WHITE );
2021-06-09 13:32:18 +00:00
2021-06-09 21:28:29 +00:00
for(int i = 0; i < arcs.size(); i+= 2)
{
SEG closestDist;
VECTOR2D ips[2];
bool collides = collideArc2Arc( arcs[i], arcs[i+1], INT_MAX, closestDist );
int ni = intersectArc2Arc( arcs[i], arcs[i+1], ips );
2021-06-09 13:32:18 +00:00
2021-06-09 21:28:29 +00:00
overlay->SetStrokeColor( WHITE );
overlay->Arc( arcs[i] );
overlay->Arc( arcs[i+1] );
2021-06-09 21:28:29 +00:00
overlay->SetStrokeColor( CYAN );
overlay->AnnotatedPoint( arcs[i].GetArcMid(), 20000 );
overlay->AnnotatedPoint( arcs[i+1].GetArcMid(), 20000 );
overlay->SetStrokeColor( MAGENTA );
2021-06-09 13:32:18 +00:00
2021-06-09 21:28:29 +00:00
for(int j = 0; j < ni; j++ )
overlay->AnnotatedPoint( ips[j], 200000 );
2021-06-09 13:32:18 +00:00
2021-06-09 21:28:29 +00:00
if( collides )
{
overlay->SetStrokeColor( YELLOW );
overlay->Line(closestDist.A, closestDist.B);
}
2021-06-09 13:32:18 +00:00
}
2021-06-09 21:28:29 +00:00
overlay = nullptr;
return 0;
}
static bool registered = UTILITY_REGISTRY::Register( {
"playground",
"Geometry/drawing playground",
playground_main_func,
} );