Commit c5973eb8 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Add documentation to .h files and update code formatting

parent c25acdbb
...@@ -11,54 +11,69 @@ TEARDROP::TEARDROP() ...@@ -11,54 +11,69 @@ TEARDROP::TEARDROP()
m_type = TEARDROP_NONE; m_type = TEARDROP_NONE;
} }
bool TEARDROP::Create(TRACK &aTrack, ENDPOINT_T endPoint, TEARDROP_TYPE type = TEARDROP_STRAIGHT)
bool TEARDROP::Create(TRACK& aTrack, ENDPOINT_T aEndPoint, TEARDROP_TYPE aType = TEARDROP_STRAIGHT )
{ {
bool result = false; bool result = false;
BOARD_CONNECTED_ITEM *anObject = GetObjectOnEnd(aTrack, endPoint); BOARD_CONNECTED_ITEM* object = getObjectOnEnd( aTrack, aEndPoint );
VIA *aVia = NULL; VIA* aVia = NULL;
if (anObject == NULL) {
if( object == NULL )
{
return false; return false;
} }
else { else
switch (anObject->Type()) { {
switch( object->Type() )
{
case PCB_VIA_T: case PCB_VIA_T:
aVia = dynamic_cast<VIA *>(anObject); aVia = dynamic_cast<VIA*>( object );
break; break;
case PCB_PAD_T: case PCB_PAD_T:
aVia = new VIA(NULL); aVia = new VIA( NULL );
aVia->SetLayer(anObject->GetLayer());
aVia->SetPosition(anObject->GetPosition()); aVia->SetLayer( object->GetLayer() );
aVia->SetWidth(2 * dynamic_cast<D_PAD *>(anObject)->GetBoundingRadius()); aVia->SetPosition( object->GetPosition() );
aVia->SetWidth( 2 * dynamic_cast<D_PAD*>( object )->GetBoundingRadius() );
break; break;
default: default:
break; break;
} }
} }
if (type == TEARDROP_STRAIGHT) { if( aType == TEARDROP_STRAIGHT )
result = StraightSegments(aTrack, *aVia, 100); {
result = straightSegments( aTrack, *aVia, 100 );
} }
else if (type == TEARDROP_CURVED) { else if( aType == TEARDROP_CURVED )
result = CurvedSegments(aTrack, *aVia); {
result = curvedSegments( aTrack, *aVia );
} }
return result; return result;
} }
bool TEARDROP::SetVector(TRACK &aTrack, const VIA & aVia, VECTOR2I &startPoint, VECTOR2I &endPoint)
bool TEARDROP::setVector(TRACK& aTrack, const VIA& aVia, VECTOR2I& aStartPoint, VECTOR2I& aEndPoint )
{ {
// Decide which end of the track is inside via and set this point as end of vector // Decide which end of the track is inside via and set this point as end of vector
STATUS_FLAGS status = aTrack.IsPointOnEnds(aVia.GetPosition(), aVia.GetWidth() / 2); STATUS_FLAGS status = aTrack.IsPointOnEnds( aVia.GetPosition(), aVia.GetWidth() / 2 );
if (status == STARTPOINT) {
startPoint = aTrack.GetEnd(); if( status == STARTPOINT )
endPoint = aTrack.GetStart(); {
aStartPoint = aTrack.GetEnd();
aEndPoint = aTrack.GetStart();
} }
else if (status == ENDPOINT) { else if( status == ENDPOINT )
startPoint = aTrack.GetStart(); {
endPoint = aTrack.GetEnd(); aStartPoint = aTrack.GetStart();
aEndPoint = aTrack.GetEnd();
} }
else { else
{
// The via is too far from any end or the track is too short // The via is too far from any end or the track is too short
return false; return false;
} }
...@@ -66,88 +81,120 @@ bool TEARDROP::SetVector(TRACK &aTrack, const VIA & aVia, VECTOR2I &startPoint, ...@@ -66,88 +81,120 @@ bool TEARDROP::SetVector(TRACK &aTrack, const VIA & aVia, VECTOR2I &startPoint,
return true; return true;
} }
bool TEARDROP::CurvedSegments(TRACK &aTrack, const VIA &aVia)
bool TEARDROP::curvedSegments( TRACK& aTrack, const VIA& aVia )
{ {
VECTOR2I startPoint(0, 0); VECTOR2I startPoint( 0, 0 );
VECTOR2I endPoint(0, 0); VECTOR2I endPoint( 0, 0 );
std::vector<VECTOR2I> upperSegment; std::vector<VECTOR2I> lowerSegment;
std::vector<VECTOR2I> lowerSegment;
if ( !SetVector(aTrack, aVia, startPoint, endPoint) ) { if( !setVector( aTrack, aVia, startPoint, endPoint ) )
{
return false; return false;
} }
// Check that the track is not too short // Check that the track is not too short
double segOutsideVia = aTrack.GetLength() - (aVia.GetWidth() / 2); double segOutsideVia = aTrack.GetLength() - (aVia.GetWidth() / 2);
double minLength = (150 * aVia.GetWidth() / 2) / 100; double minLength = (150 * aVia.GetWidth() / 2) / 100;
if (segOutsideVia < minLength) {
if( segOutsideVia < minLength )
{
return false; return false;
} }
VECTOR2I point(0, 0); VECTOR2I point( 0, 0 );
VECTOR2I viaCenter(aVia.GetPosition().x, aVia.GetPosition().y); VECTOR2I viaCenter( aVia.GetPosition().x, aVia.GetPosition().y );
VECTOR2I apertureUpper(0, 0); VECTOR2I apertureUpper( 0, 0 );
VECTOR2I apertureLower(0, 0); VECTOR2I apertureLower( 0, 0 );
double radius = (aVia.GetWidth() / 2) - (aTrack.GetWidth() / 2); double radius = (aVia.GetWidth() / 2) - (aTrack.GetWidth() / 2);
double rotationAngle = VECTOR2I(startPoint - endPoint).Angle(); double rotationAngle = VECTOR2I( startPoint - endPoint ).Angle();
// Calculate the segments of deltoid composing the outline of a teardrop // Calculate the segments of deltoid composing the outline of a teardrop
for ( int i = 10; i <= 60; i = i + 10 ) { for( int i = 0; i <= 60; i = i + 10 )
PointOnCurve(i, radius, point); {
point = point.Rotate(rotationAngle); pointOnCurve( i, radius, point );
point = point.Rotate( rotationAngle );
point += viaCenter; point += viaCenter;
m_coordinates.push_back(point); m_coordinates.push_back( point );
if (i == 50) {
if( i == 50 )
{
apertureUpper = point; apertureUpper = point;
} }
} }
for ( int i = 300; i <= 350; i = i + 10 ) {
PointOnCurve(i, radius, point); for( int i = 300; i <= 360; i = i + 10 )
point = point.Rotate(rotationAngle); {
pointOnCurve( i, radius, point );
point = point.Rotate( rotationAngle );
point += viaCenter; point += viaCenter;
m_coordinates.push_back(point); m_coordinates.push_back( point );
if (i == 340) {
if( i == 340 )
{
apertureLower = point; apertureLower = point;
} }
} }
// Calculate the number of segments needed to fill the area inside the teardrop // Calculate the number of segments needed to fill the area inside the teardrop
if (aVia.GetWidth() / 2 > 2 * aTrack.GetWidth()) { if( aVia.GetWidth() / 2 > 2 * aTrack.GetWidth() )
{
// First, calculate the distance between two points on both sides of the track and // First, calculate the distance between two points on both sides of the track and
// number of iterations required to fill the zone // number of iterations required to fill the zone
SEG aperture(apertureUpper, apertureLower); SEG aperture( apertureUpper, apertureLower );
int numSegments = aperture.Length() / aTrack.GetWidth(); int numSegments = aperture.Length() / aTrack.GetWidth();
int delta = radius / numSegments; int delta = radius / numSegments;
for (int iteration = 0; iteration < numSegments; iteration++) {
// Second, fill the inward teardrop area
for( int iteration = 0; iteration < numSegments; iteration++ )
{
radius = radius - delta; radius = radius - delta;
for ( int i = 10; i <= 60; i = i + 10 ) { for( int i = 10; i <= 60; i = i + 10 )
PointOnCurve(i, radius, point); {
point = point.Rotate(rotationAngle); pointOnCurve( i, radius, point );
point = point.Rotate( rotationAngle );
point += viaCenter; point += viaCenter;
if (i == 10) {
int distance = SEG(viaCenter, point).Length(); // Stop calculations in case the coordinates are inside the via
if (distance < aVia.GetWidth() / 2) { if( i == 10 )
{
int distance = SEG( viaCenter, point ).Length();
if( distance < aVia.GetWidth() / 2 )
{
break; break;
} }
} }
m_coordinates.push_back(point); m_coordinates.push_back( point );
} }
lowerSegment.clear(); lowerSegment.clear();
for ( int i = 350; i >= 300; i = i - 10 ) { for( int i = 350; i >= 300; i = i - 10 )
PointOnCurve(i, radius, point); {
point = point.Rotate(rotationAngle); pointOnCurve( i, radius, point );
point = point.Rotate( rotationAngle );
point += viaCenter; point += viaCenter;
if (i == 350) {
int distance = SEG(viaCenter, point).Length(); // Stop calculations in case the coordinates are inside the via
if (distance < aVia.GetWidth() / 2) { if( i == 350 )
{
int distance = SEG( viaCenter, point ).Length();
if( distance < aVia.GetWidth() / 2 )
{
break; break;
} }
} }
lowerSegment.push_back(point); lowerSegment.push_back( point );
} }
// Revert coordinates order
for (std::vector<VECTOR2I>::reverse_iterator iter = lowerSegment.rbegin(); iter != lowerSegment.rend(); ++iter) { // Revert coordinates order. This is necessary to create tracks in correct order later on
m_coordinates.push_back(*iter); for( std::vector<VECTOR2I>::reverse_iterator iter = lowerSegment.rbegin();
iter != lowerSegment.rend();
++iter )
{
m_coordinates.push_back( *iter );
} }
} }
} }
...@@ -155,140 +202,173 @@ bool TEARDROP::CurvedSegments(TRACK &aTrack, const VIA &aVia) ...@@ -155,140 +202,173 @@ bool TEARDROP::CurvedSegments(TRACK &aTrack, const VIA &aVia)
return true; return true;
} }
bool TEARDROP::StraightSegments(TRACK &aTrack, const VIA &aVia, int distance = 100)
bool TEARDROP::straightSegments(TRACK& aTrack, const VIA& aVia, int aDistance = 100 )
{ {
VECTOR2I startPoint(0, 0); VECTOR2I startPoint( 0, 0 );
VECTOR2I endPoint(0, 0); VECTOR2I endPoint( 0, 0 );
VECTOR2I viaCenter(aVia.GetPosition().x, aVia.GetPosition().y); VECTOR2I viaCenter( aVia.GetPosition().x, aVia.GetPosition().y );
if ( !SetVector(aTrack, aVia, startPoint, endPoint) ) { if( !setVector( aTrack, aVia, startPoint, endPoint ) )
{
return false; return false;
} }
// Check that the track is not too short // Check that the track is not too short
double segOutsideVia = aTrack.GetLength() - (aVia.GetWidth() / 2); double segOutsideVia = aTrack.GetLength() - (aVia.GetWidth() / 2);
double minLength = (distance * aVia.GetWidth() / 2) / 100; double minLength = (aDistance * aVia.GetWidth() / 2) / 100;
if (segOutsideVia < minLength) {
if( segOutsideVia < minLength )
{
return false; return false;
} }
// Equation coefficients // Equation coefficients
double r = (aVia.GetWidth() / 2) + ((distance * aVia.GetWidth()) / (2 *100)); double r = (aVia.GetWidth() / 2) + ( (aDistance * aVia.GetWidth()) / (2 * 100) );
double a = pow((endPoint.x - startPoint.x), 2) + pow((endPoint.y - startPoint.y), 2); double a = pow( (endPoint.x - startPoint.x), 2 ) + pow( (endPoint.y - startPoint.y), 2 );
double b = 2 * (double)(endPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) + 2 * (double)(endPoint.y - startPoint.y) * (double)(startPoint.y - viaCenter.y); double b = 2 * (double)(endPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) +
double c = pow((startPoint.x - viaCenter.x), 2) + pow((startPoint.y - viaCenter.y), 2) - pow(r, 2); 2 * (double)(endPoint.y - startPoint.y) * (double)(startPoint.y - viaCenter.y);
double t = 2 * c / (-b + sqrt(b * b - 4 * a * c)); double c = pow( (startPoint.x - viaCenter.x), 2 ) + pow( (startPoint.y - viaCenter.y), 2 ) - pow( r, 2 );
double t = 2 * c / (-b + sqrt( b * b - 4 * a * c));
double x = (endPoint.x - startPoint.x) * t + startPoint.x; double x = (endPoint.x - startPoint.x) * t + startPoint.x;
double y = (endPoint.y - startPoint.y) * t + startPoint.y; double y = (endPoint.y - startPoint.y) * t + startPoint.y;
VECTOR2I linePoint(x, y); VECTOR2I linePoint( x, y );
int correctedRadius = (aVia.GetWidth() / 2) - (aTrack.GetWidth() / 2); int correctedRadius = (aVia.GetWidth() / 2) - (aTrack.GetWidth() / 2);
c = pow((startPoint.x - viaCenter.x), 2) + pow((startPoint.y - viaCenter.y), 2) - pow(correctedRadius, 2); c = pow( (startPoint.x - viaCenter.x), 2 ) + pow( (startPoint.y - viaCenter.y), 2 ) - pow( correctedRadius, 2 );
t = 2 * c / (-b + sqrt(b * b - 4 * a * c)); t = 2 * c / (-b + sqrt( b * b - 4 * a * c ));
x = (endPoint.x - startPoint.x) * t + startPoint.x; x = (endPoint.x - startPoint.x) * t + startPoint.x;
y = (endPoint.y - startPoint.y) * t + startPoint.y; y = (endPoint.y - startPoint.y) * t + startPoint.y;
VECTOR2I circlePoint(x, y); VECTOR2I circlePoint( x, y );
VECTOR2I upperPoint = circlePoint - viaCenter; VECTOR2I upperPoint = circlePoint - viaCenter;
VECTOR2I lowerPoint = upperPoint; VECTOR2I lowerPoint = upperPoint;
upperPoint = upperPoint.Rotate(M_PI / 2); upperPoint = upperPoint.Rotate( M_PI / 2 );
lowerPoint = lowerPoint.Rotate(-M_PI / 2); lowerPoint = lowerPoint.Rotate( -M_PI / 2 );
upperPoint += viaCenter; upperPoint += viaCenter;
lowerPoint += viaCenter; lowerPoint += viaCenter;
// Calculate the number of segments needed to fill the area inside the teardrop // Calculate the number of segments needed to fill the area inside the teardrop
std::vector<VECTOR2I> splitPoints; std::vector<VECTOR2I> splitPoints;
if (aVia.GetWidth() / 2 > 2 * aTrack.GetWidth()) {
if( aVia.GetWidth() / 2 > 2 * aTrack.GetWidth() )
{
// First, calculate the intersection point of the circle and one hand of the teardrop // First, calculate the intersection point of the circle and one hand of the teardrop
r = aVia.GetWidth() / 2; r = aVia.GetWidth() / 2;
a = pow((upperPoint.x - startPoint.x), 2) + pow((upperPoint.y - startPoint.y), 2); a = pow( (upperPoint.x - startPoint.x), 2 ) + pow( (upperPoint.y - startPoint.y), 2 );
b = 2 * (double)(upperPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) + 2 * (double)(upperPoint.y - startPoint.y) * (double)(startPoint.y - viaCenter.y); b = 2 * (double)(upperPoint.x - startPoint.x) * (double)(startPoint.x - viaCenter.x) +
c = pow((startPoint.x - viaCenter.x), 2) + pow((startPoint.y - viaCenter.y), 2) - pow(r, 2); 2 * (double)(upperPoint.y - startPoint.y) * (double) (startPoint.y - viaCenter.y);
t = 2 * c / (-b + sqrt(b * b - 4 * a * c)); c = pow( (startPoint.x - viaCenter.x), 2 ) + pow( (startPoint.y - viaCenter.y), 2 ) - pow( r, 2 );
t = 2 * c / ( -b + sqrt( b * b - 4 * a * c ) );
x = (upperPoint.x - startPoint.x) * t + startPoint.x; x = (upperPoint.x - startPoint.x) * t + startPoint.x;
y = (upperPoint.y - startPoint.y) * t + startPoint.y; y = (upperPoint.y - startPoint.y) * t + startPoint.y;
VECTOR2I intersectionPoint((int)x, (int)y); VECTOR2I intersectionPoint( (int) x, (int) y );
// Second, calculate the distance between the given track and the intersection point // Second, calculate the distance between the given track and the intersection point
SEG trackSegment(aTrack.GetStart().x, aTrack.GetStart().y, aTrack.GetEnd().x, aTrack.GetEnd().y); SEG trackSegment( aTrack.GetStart().x, aTrack.GetStart().y,
int dist = trackSegment.LineDistance(intersectionPoint); aTrack.GetEnd().x, aTrack.GetEnd().y );
int dist = trackSegment.LineDistance( intersectionPoint );
int numSegments = 2 * dist / aTrack.GetWidth(); int numSegments = 2 * dist / aTrack.GetWidth();
// Third, subdivide the diameter of the via and build additional segments // Third, subdivide the diameter of the via and build additional segments
SEG segDiameter = SEG(upperPoint, lowerPoint); SEG segDiameter = SEG( upperPoint, lowerPoint );
SplitSegment(segDiameter, numSegments, splitPoints); splitSegment( segDiameter, numSegments, splitPoints );
} }
std::list<VECTOR2I> outlinePoints; std::list<VECTOR2I> outlinePoints;
outlinePoints.push_back(upperPoint); outlinePoints.push_back( upperPoint );
for (size_t i = 0; i < splitPoints.size(); i++) { for( size_t i = 0; i < splitPoints.size(); i++ )
outlinePoints.push_back(splitPoints[i]); {
outlinePoints.push_back( splitPoints[i] );
} }
outlinePoints.push_back(lowerPoint); outlinePoints.push_back( lowerPoint );
// Biuld triangles filling the teardrop // Biuld triangles filling the teardrop
int vertexNum = 0; int vertexNum = 0;
std::list<VECTOR2I>::iterator iter = outlinePoints.begin(); std::list<VECTOR2I>::iterator iter = outlinePoints.begin();
while ( iter != outlinePoints.end() ) { while( iter != outlinePoints.end() )
switch (vertexNum) { {
switch( vertexNum )
{
case 0: case 0:
m_coordinates.push_back(linePoint); m_coordinates.push_back( linePoint );
vertexNum++; vertexNum++;
break; break;
case 1: case 1:
m_coordinates.push_back(*iter); m_coordinates.push_back( *iter );
vertexNum++; vertexNum++;
iter++; iter++;
break; break;
case 2: case 2:
m_coordinates.push_back(*iter); m_coordinates.push_back( *iter );
vertexNum = 0; vertexNum = 0;
iter++; iter++;
break; break;
default:break;
default:
break;
} }
} }
// Append additional vertexies in order to finish last triangle // Append additional vertexies in order to finish last triangle
if (vertexNum == 0) { if( vertexNum == 0 )
m_coordinates.push_back(linePoint); {
m_coordinates.push_back( linePoint );
} }
else if (vertexNum == 2) { else if( vertexNum == 2 )
m_coordinates.push_back(m_coordinates[m_coordinates.size() - 3]); {
m_coordinates.push_back(linePoint); m_coordinates.push_back( m_coordinates[m_coordinates.size() - 3] );
m_coordinates.push_back( linePoint );
} }
return true; return true;
} }
// TODO: m_TracksConnected member is considered a temporary storage. Find another way to get an object // TODO: m_TracksConnected member is considered a temporary storage. Find another way to get an object
BOARD_CONNECTED_ITEM* TEARDROP::GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoint) BOARD_CONNECTED_ITEM* TEARDROP::getObjectOnEnd(TRACK& aTrack, ENDPOINT_T aEndPoint )
{ {
wxPoint trackPoint; wxPoint trackPoint;
BOARD_CONNECTED_ITEM *item = NULL; BOARD_CONNECTED_ITEM* item = NULL;
std::vector<TRACK *>::const_iterator iter; std::vector<TRACK*>::const_iterator iter;
if (endPoint == ENDPOINT_START) { if( aEndPoint == ENDPOINT_START )
{
trackPoint = aTrack.GetStart(); trackPoint = aTrack.GetStart();
} }
else { else
{
trackPoint = aTrack.GetEnd(); trackPoint = aTrack.GetEnd();
} }
// Check for vias first // Check for vias first
for (iter = aTrack.m_TracksConnected.begin(); iter != aTrack.m_TracksConnected.end(); ++iter) { for( iter = aTrack.m_TracksConnected.begin(); iter != aTrack.m_TracksConnected.end(); ++iter )
{
KICAD_T type = (*iter)->Type(); KICAD_T type = (*iter)->Type();
bool hitTest = (*iter)->HitTest(trackPoint); bool hitTest = (*iter)->HitTest( trackPoint );
if (type == PCB_VIA_T && hitTest == true) {
if( (type == PCB_VIA_T) && (hitTest == true) )
{
item = *iter; item = *iter;
} }
} }
// Check for pads if via was not found on this end of the track // Check for pads if via was not found on this end of the track
if (item == NULL) { if( item == NULL )
for (std::vector<D_PAD *>::iterator iter = aTrack.m_PadsConnected.begin(); iter != aTrack.m_PadsConnected.end(); ++iter) { {
for( std::vector<D_PAD*>::iterator iter = aTrack.m_PadsConnected.begin();
iter != aTrack.m_PadsConnected.end();
++iter )
{
PAD_SHAPE_T shape = (*iter)->GetShape(); PAD_SHAPE_T shape = (*iter)->GetShape();
bool hitTest = (*iter)->HitTest(trackPoint); bool hitTest = (*iter)->HitTest( trackPoint );
if (shape == PAD_CIRCLE && hitTest == true) {
if( shape == PAD_CIRCLE && hitTest == true )
{
item = *iter; item = *iter;
} }
} }
...@@ -297,20 +377,28 @@ BOARD_CONNECTED_ITEM* TEARDROP::GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoin ...@@ -297,20 +377,28 @@ BOARD_CONNECTED_ITEM* TEARDROP::GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoin
return item; return item;
} }
void TEARDROP::SplitSegment(const SEG &segment, int splits, std::vector<VECTOR2I> &points)
void TEARDROP::splitSegment( const SEG& aSegment, int aSplits, std::vector<VECTOR2I>& aPoints )
{ {
int dX = abs((segment.A.x - segment.B.x) / splits); int dX = abs( (aSegment.A.x - aSegment.B.x) / aSplits );
int dY = abs((segment.A.y - segment.B.y) / splits); int dY = abs( (aSegment.A.y - aSegment.B.y) / aSplits );
if (segment.A.x > segment.B.x) {
if( aSegment.A.x > aSegment.B.x )
{
dX = -dX; dX = -dX;
} }
if (segment.A.y > segment.B.y) {
if( aSegment.A.y > aSegment.B.y )
{
dY = -dY; dY = -dY;
} }
VECTOR2I delta(dX, dY);
points.push_back(segment.A + delta); VECTOR2I delta( dX, dY );
aPoints.push_back( aSegment.A + delta );
// The last point is excluded as it will coinside with already built tracks // The last point is excluded as it will coinside with already built tracks
for (int i = 1; i < splits - 1; i++) { for( int i = 1; i < aSplits - 1; i++ )
points.push_back(points.back() + delta); {
aPoints.push_back( aPoints.back() + delta );
} }
} }
...@@ -17,93 +17,130 @@ ...@@ -17,93 +17,130 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
* @file class_teardrop.h
* @brief Definitions for teardrops.
*/
#ifndef CLASS_TEARDROP_H #ifndef CLASS_TEARDROP_H
#define CLASS_TEARDROP_H #define CLASS_TEARDROP_H
#include "class_track.h" #include "class_track.h"
#include "geometry/seg.h" #include "geometry/seg.h"
/**
* @brief The TEARDROP class
* is base definition of a teardrop. It is intended for calculation and holding of points which
* compose a teardrop. This class does not contain any methods which create actual tracks.
*/
class TEARDROP class TEARDROP
{ {
public: public:
TEARDROP(); TEARDROP();
/** /**
* @brief Defines the type of a teardrop. * @brief The TEARDROP_TYPE defines the type of a teardrop.
*/ */
typedef enum { typedef enum
TEARDROP_NONE, ///< The type is undefined {
TEARDROP_STRAIGHT, ///< The teardrop is created by two straight segments TEARDROP_NONE, ///< The type is undefined
TEARDROP_CURVED ///< The teardrop is created by several segments approximating a curve TEARDROP_STRAIGHT, ///< The teardrop is created by two straight segments
TEARDROP_CURVED ///< The teardrop is created by several segments approximating a curve
} TEARDROP_TYPE; } TEARDROP_TYPE;
/** /**
* @brief GetType returns the type of the teardrop. * @brief Function \a GetType
* @return TEARDROP_TYPE * returns the type of the teardrop.
* @return TEARDROP_TYPE - the type of the teardrop
*/ */
TEARDROP_TYPE GetType() const {return m_type;} TEARDROP_TYPE GetType() const { return m_type; }
/** /**
* @brief Function Create creates a teardrop(s) for a given track * @brief Function \a Create
* @param aTrack * creates a teardrop(s) for a given track.
* @return \a true in case the teardrops were successfully built and \a false otherwise * @param [in] aTrack is a track at which teardrop(s) should be created
* @param [in] aEndPoint is an end point at which a teardrop should be created
* @param [in] aType defines the type of a teardrop
* @return bool - \a true in case the teardrops were successfully built and \a false otherwise
*/ */
bool Create(TRACK &aTrack, ENDPOINT_T endPoint, TEARDROP_TYPE type); bool Create( TRACK& aTrack, ENDPOINT_T aEndPoint, TEARDROP_TYPE aType );
void GetCoordinates(std::vector<VECTOR2I> &points) const {points = m_coordinates;} /**
* @brief Function \a GetCoordinates
* returns the coordinates of created teardrop.
* @param [out] aPoints is a container for coordinates
*/
void GetCoordinates( std::vector<VECTOR2I>& aPoints ) const { aPoints = m_coordinates; }
private: private:
///> Contains the type of teardrop /// Contains the type of teardrop
TEARDROP_TYPE m_type; TEARDROP_TYPE m_type;
///> \a m_upperSegment and \a m_lowerSegment contain coordinates of segments composing a teardrop /// Contains the actual coordinates of teardrop
std::vector<VECTOR2I> m_upperSegment;
std::vector<VECTOR2I> m_lowerSegment;
std::vector<VECTOR2I> m_coordinates; std::vector<VECTOR2I> m_coordinates;
/** /**
* @brief Function \a CurvedSegments computes several points on deltoid curve and moves * @brief Function \a curvedSegments
* these points along the vector defined by \a aTrack. * computes several points on deltoid curve and moves these points along the vector
* defined by \a aTrack.
* *
* This function computes the coordinates of points only and does not build actual track segments. * This function computes the coordinates of points only and does not build actual track segments.
* See deltiod description and its parametric equations on [wiki page](http://en.wikipedia.org/wiki/Deltoid_curve). * See deltiod description and its parametric equations on [wiki page](http://en.wikipedia.org/wiki/Deltoid_curve).
* @param [in] aTrack defines a vector along which the curved segments should be built * @param [in] aTrack defines a vector along which the curved segments should be built
* @param [in] aVia used as the center of coordinates * @param [in] aVia used as the center of coordinates
* @return \a true in case the segments were successfully built and \a false otherwise * @return bool - \a true in case the segments were successfully built and \a false otherwise
*/ */
bool CurvedSegments(TRACK &aTrack, const VIA &aVia); bool curvedSegments( TRACK& aTrack, const VIA& aVia );
/** /**
* @brief Function \a StraightSegments builds two tangent lines for a circle from a givent point. * @brief Function \a straightSegments
* builds two tangent lines to a circle from a givent point.
* *
* This function computes the coordinates of points only and does not build actual track segments. * This function computes the coordinates of points only and does not build actual track segments.
* @param [in] aTrack defines a vector along which the segments should be built * @param [in] aTrack defines a vector along which the segments should be built
* @param [in] aVia represents a circle to which the segments should be built * @param [in] aVia represents a circle to which the segments should be built
* @param [in] distance is distance ratio (in percent) from circle center in respect to its diameter * @param [in] aDistance is distance ratio (in percent) from circle center in respect to its diameter
* @return \a true in case the segments were successfully built and \a false otherwise * @return bool - \a true in case the segments were successfully built and \a false otherwise
*/
bool straightSegments( TRACK& aTrack, const VIA& aVia, int aDistance );
/**
* @brief Function \a setVector
* creates a vector from \a aTrack directed into \a aVia.
* @param [in] aTrack is used to create a vector
* @param [in] aVia is an object to which the vector should be pointed to
* @param [out] aStartPoint is start point of resulting vector
* @param [out] aEndPoint is end point of resulting vector
* @return bool - \a true in case the vector is created successfully and \a false otherwise
*/
bool setVector( TRACK& aTrack, const VIA& aVia, VECTOR2I& aStartPoint, VECTOR2I& aEndPoint );
/**
* @brief Function \a getObjectOnEnd
* returns an object (via or pad) at the given end of a track.
* @param [in] aTrack is a reference track
* @param [in] aEndPoint defines the end in question
* @return BOARD_CONNECTED_ITEM - the object found or NULL otherwise
*/ */
bool StraightSegments(TRACK &aTrack, const VIA &aVia, int distance); BOARD_CONNECTED_ITEM* getObjectOnEnd( TRACK& aTrack, ENDPOINT_T aEndPoint );
/** /**
* @brief Function SetVector creates a vector from \a aTrack directed into \a aVia * @brief Function \a splitSegment
* @param aTrack is used to create a vector * splits a segment into given number of subsegments.
* @param startPoint is start point of resulting vector * @param [in] aSegment is a segment to be split
* @param endPoint is end point of resulting vector * @param [i] aSplits is a number of splits
* @return \a true in case the vector is created successfully and \a false otherwise * @param [out] aPoints is a container for split points
*/ */
bool SetVector(TRACK &aTrack, const VIA &aVia, VECTOR2I &startPoint, VECTOR2I &endPoint); void splitSegment( const SEG& aSegment, int aSplits, std::vector<VECTOR2I>& aPoints );
BOARD_CONNECTED_ITEM* GetObjectOnEnd(TRACK &aTrack, ENDPOINT_T endPoint); /**
void SplitSegment(const SEG &segment, int splits, std::vector<VECTOR2I> &points); * @brief Function \a pointOnCurve
inline void PointOnCurve(int angle, double radius, VECTOR2I &point) { * calculates a single point on a deltoid curve.
* @param [in] aAngle is an angle at which the point should be calculated
* @param [in] aRadius is the radius of a rolling circle
* @param [out] aPoint is a container for calculated point
*/
inline void pointOnCurve( int aAngle, double aRadius, VECTOR2I& aPoint )
{
double coeff = M_PI / 180.0; double coeff = M_PI / 180.0;
point.x = 2 * radius * cos(coeff * angle) + radius * cos(2 * coeff * angle);
point.y = 2 * radius * sin(coeff * angle) - radius * sin(2 * coeff * angle); aPoint.x = 2 * aRadius * cos( coeff * aAngle ) + aRadius * cos( 2 * coeff * aAngle );
aPoint.y = 2 * aRadius * sin( coeff * aAngle ) - aRadius * sin( 2 * coeff * aAngle );
} }
}; };
#endif // CLASS_TEARDROP_H #endif // CLASS_TEARDROP_H
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Elphel, Inc.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "dialog_teardrops.h" #include "dialog_teardrops.h"
DIALOG_TEARDROPS::DIALOG_TEARDROPS(PCB_EDIT_FRAME *aParent, TEARDROPS_SETTINGS *settings): DIALOG_TEARDROPS::DIALOG_TEARDROPS(PCB_EDIT_FRAME *aParent, TEARDROPS_SETTINGS *aSettings = NULL ):
DIALOG_TEARDROPS_BASE(aParent) DIALOG_TEARDROPS_BASE( aParent )
{ {
m_parent = aParent; m_parent = aParent;
m_settings = settings; m_settings = aSettings;
if (m_settings != NULL) { if( m_settings != NULL )
InitDialogSettings(); {
initDialogSettings();
} }
} }
void DIALOG_TEARDROPS::InitDialogSettings() void DIALOG_TEARDROPS::initDialogSettings()
{ {
wxASSERT(m_settings != NULL); assert(m_settings != NULL);
if (m_modeRemove->GetValue() == true) {
if( m_modeRemove->GetValue() == true )
{
m_settings->m_mode = TEARDROPS_MODE_REMOVE; m_settings->m_mode = TEARDROPS_MODE_REMOVE;
} }
else { else
{
m_settings->m_mode = TEARDROPS_MODE_ADD; m_settings->m_mode = TEARDROPS_MODE_ADD;
} }
if (m_tracksAll->GetValue() == true) { if( m_tracksAll->GetValue() == true )
{
m_settings->m_track = TEARDROPS_TRACKS_ALL; m_settings->m_track = TEARDROPS_TRACKS_ALL;
} }
else { else
{
m_settings->m_track = TEARDROPS_TRACKS_SELECTED; m_settings->m_track = TEARDROPS_TRACKS_SELECTED;
} }
m_settings->m_type = static_cast<TEARDROPS_TYPE>(m_choiceStyle->GetSelection()); m_settings->m_type = static_cast<TEARDROPS_TYPE>( m_choiceStyle->GetSelection() );
m_settings->m_scope = TEARDROPS_SCOPE_NONE; m_settings->m_scope = TEARDROPS_SCOPE_NONE;
if (m_scopeVias->IsChecked() == true) { if( m_scopeVias->IsChecked() == true )
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope | TEARDROPS_SCOPE_VIAS); {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope | TEARDROPS_SCOPE_VIAS );
} }
if (m_scopePads->IsChecked() == true) { if( m_scopePads->IsChecked() == true )
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope | TEARDROPS_SCOPE_PADS); {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope | TEARDROPS_SCOPE_PADS );
} }
if (m_scopeTracks->IsChecked() == true) { if( m_scopeTracks->IsChecked() == true )
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope | TEARDROPS_SCOPE_TRACKS); {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope | TEARDROPS_SCOPE_TRACKS );
} }
m_settings->m_clearSelection = m_checkClear->IsChecked(); m_settings->m_clearSelection = m_checkClear->IsChecked();
m_settings->m_ignoreDrc = m_checkIgnore->IsChecked(); m_settings->m_ignoreDrc = m_checkIgnore->IsChecked();
} }
void DIALOG_TEARDROPS::OnModeAdd(wxCommandEvent &event) void DIALOG_TEARDROPS::OnModeAdd( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
{
m_settings->m_mode = TEARDROPS_MODE_ADD; m_settings->m_mode = TEARDROPS_MODE_ADD;
LockOptionsControls(false); lockOptionsControls( false );
LockTracksControls(false); lockTracksControls( false );
LockScopeControls(false); lockScopeControls( false );
} }
} }
void DIALOG_TEARDROPS::OnModeRemove(wxCommandEvent &event) void DIALOG_TEARDROPS::OnModeRemove( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
{
m_settings->m_mode = TEARDROPS_MODE_REMOVE; m_settings->m_mode = TEARDROPS_MODE_REMOVE;
LockOptionsControls(true); lockOptionsControls( true );
LockTracksControls(true); lockTracksControls( true );
LockScopeControls(true); lockScopeControls( true );
} }
} }
void DIALOG_TEARDROPS::OnTracksAll(wxCommandEvent &event) void DIALOG_TEARDROPS::OnTracksAll( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
{
m_settings->m_track = TEARDROPS_TRACKS_ALL; m_settings->m_track = TEARDROPS_TRACKS_ALL;
} }
m_checkClear->Enable(false); m_checkClear->Enable( false );
} }
void DIALOG_TEARDROPS::OnTracksSelected(wxCommandEvent &event) void DIALOG_TEARDROPS::OnTracksSelected( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
{
m_settings->m_track = TEARDROPS_TRACKS_SELECTED; m_settings->m_track = TEARDROPS_TRACKS_SELECTED;
} }
m_checkClear->Enable(true); m_checkClear->Enable( true );
} }
void DIALOG_TEARDROPS::OnScopeVias(wxCommandEvent &event) void DIALOG_TEARDROPS::OnScopeVias( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
if (m_scopeVias->IsChecked()) { {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope | TEARDROPS_SCOPE_VIAS); if( m_scopeVias->IsChecked() )
{
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope | TEARDROPS_SCOPE_VIAS );
} }
else { else
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope & (~TEARDROPS_SCOPE_VIAS)); {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope & (~TEARDROPS_SCOPE_VIAS) );
} }
} }
} }
void DIALOG_TEARDROPS::OnScopePads(wxCommandEvent &event) void DIALOG_TEARDROPS::OnScopePads( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
if (m_scopePads->IsChecked()) { {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope | TEARDROPS_SCOPE_PADS); if( m_scopePads->IsChecked() )
{
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope | TEARDROPS_SCOPE_PADS );
} }
else { else
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>(m_settings->m_scope & (~TEARDROPS_SCOPE_PADS)); {
m_settings->m_scope = static_cast<TEARDROPS_SCOPE>( m_settings->m_scope & (~TEARDROPS_SCOPE_PADS) );
} }
} }
} }
void DIALOG_TEARDROPS::OnStyleChanged(wxCommandEvent &event) void DIALOG_TEARDROPS::OnStyleChanged( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
m_settings->m_type = static_cast<TEARDROPS_TYPE>(m_choiceStyle->GetSelection()); {
m_settings->m_type = static_cast<TEARDROPS_TYPE>( m_choiceStyle->GetSelection() );
} }
} }
void DIALOG_TEARDROPS::OnClearSelection(wxCommandEvent &event) void DIALOG_TEARDROPS::OnClearSelection( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
{
m_settings->m_clearSelection = m_checkClear->IsChecked(); m_settings->m_clearSelection = m_checkClear->IsChecked();
} }
} }
void DIALOG_TEARDROPS::OnIgnoreDrc(wxCommandEvent &event) void DIALOG_TEARDROPS::OnIgnoreDrc( wxCommandEvent &aEvent )
{ {
event.Skip(); aEvent.Skip();
if (m_settings != NULL) { if( m_settings != NULL )
{
m_settings->m_ignoreDrc = m_checkIgnore->IsChecked(); m_settings->m_ignoreDrc = m_checkIgnore->IsChecked();
} }
} }
void DIALOG_TEARDROPS::LockOptionsControls(bool state) void DIALOG_TEARDROPS::lockOptionsControls( bool state )
{ {
if (state == true) { if( state == true )
if (m_tracksSelected->GetValue() == false) { {
m_checkClear->Enable(false); if( m_tracksSelected->GetValue() == false )
{
m_checkClear->Enable( false );
} }
m_checkIgnore->Enable(false); m_checkIgnore->Enable( false );
m_choiceStyle->Enable(false); m_choiceStyle->Enable( false );
} }
else { else
if (m_tracksSelected->GetValue() == true) { {
m_checkClear->Enable(true); if( m_tracksSelected->GetValue() == true )
{
m_checkClear->Enable( true );
} }
m_checkIgnore->Enable(true); m_checkIgnore->Enable( true );
m_choiceStyle->Enable(true); m_choiceStyle->Enable( true );
} }
} }
void DIALOG_TEARDROPS::LockTracksControls(bool state) void DIALOG_TEARDROPS::lockTracksControls( bool state )
{ {
if (state == true) { if( state == true )
m_tracksAll->Enable(false); {
m_tracksSelected->Enable(false); m_tracksAll->Enable( false );
m_tracksSelected->Enable( false );
} }
else { else
m_tracksAll->Enable(true); {
m_tracksSelected->Enable(true); m_tracksAll->Enable( true );
m_tracksSelected->Enable( true );
} }
} }
void DIALOG_TEARDROPS::LockScopeControls(bool state) void DIALOG_TEARDROPS::lockScopeControls( bool state )
{ {
if (state == true) { if( state == true )
m_scopePads->Enable(false); {
m_scopeVias->Enable(false); m_scopePads->Enable( false );
} m_scopeVias->Enable( false );
else { }
m_scopePads->Enable(true); else
m_scopeVias->Enable(true); {
m_scopePads->Enable( true );
m_scopeVias->Enable( true );
} }
} }
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Elphel, Inc.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef DIALOG_TEARDROPS_H #ifndef DIALOG_TEARDROPS_H
#define DIALOG_TEARDROPS_H #define DIALOG_TEARDROPS_H
...@@ -5,56 +24,108 @@ ...@@ -5,56 +24,108 @@
#include "dialog_teardrops_base.h" #include "dialog_teardrops_base.h"
#include "wxPcbStruct.h" #include "wxPcbStruct.h"
/**
* @brief The DIALOG_TEARDROPS class
* implements teardrop management dialog for current board.
*/
class DIALOG_TEARDROPS : public DIALOG_TEARDROPS_BASE class DIALOG_TEARDROPS : public DIALOG_TEARDROPS_BASE
{ {
public: public:
typedef enum { /**
* @brief The TEARDROPS_MODE
* defines an action to be performed on teardrops.
*/
typedef enum
{
/// Teardrops addition mode
TEARDROPS_MODE_ADD, TEARDROPS_MODE_ADD,
/// Teardrops removal mode
TEARDROPS_MODE_REMOVE TEARDROPS_MODE_REMOVE
} TEARDROPS_MODE; } TEARDROPS_MODE;
typedef enum {
/**
* @brief The TEARDROPS_TRACKS
* determines selection processing.
*/
typedef enum
{
/// Process all tracks
TEARDROPS_TRACKS_ALL, TEARDROPS_TRACKS_ALL,
/// Process selected tracks only
TEARDROPS_TRACKS_SELECTED TEARDROPS_TRACKS_SELECTED
} TEARDROPS_TRACKS; } TEARDROPS_TRACKS;
typedef enum {
/**
* @brief The TEARDROPS_TYPE
* defines the shape of teardrops.
*/
typedef enum
{
/// The shape is not defined
TEARDROPS_TYPE_NONE = -1, TEARDROPS_TYPE_NONE = -1,
/// The teardops have straight outlines
TEARDROPS_TYPE_STRAIGHT, TEARDROPS_TYPE_STRAIGHT,
/// The teardrops have curved outlines
TEARDROPS_TYPE_CURVED TEARDROPS_TYPE_CURVED
} TEARDROPS_TYPE; } TEARDROPS_TYPE;
typedef enum {
/**
* @brief The TEARDROPS_SCOPE
* defines the types of objects for which teardrops should be created. This is a bit field, each
* bit correcponds to an object type.
*/
typedef enum
{
/// No objects are specified
TEARDROPS_SCOPE_NONE, TEARDROPS_SCOPE_NONE,
/// Create teardrops for vias
TEARDROPS_SCOPE_VIAS = 1, TEARDROPS_SCOPE_VIAS = 1,
/// Create teardrops for pads
TEARDROPS_SCOPE_PADS = 2, TEARDROPS_SCOPE_PADS = 2,
/// Create teardrops for tracks (not implemented yet)
TEARDROPS_SCOPE_TRACKS = 4 TEARDROPS_SCOPE_TRACKS = 4
} TEARDROPS_SCOPE; } TEARDROPS_SCOPE;
typedef struct {
/**
* @brief The TEARDROPS_SETTINGS
* class is a container for all the settings specified by the user.
*/
typedef struct
{
/// The action to be performed (addition, deletion)
TEARDROPS_MODE m_mode; TEARDROPS_MODE m_mode;
/// Process selection
TEARDROPS_TRACKS m_track; TEARDROPS_TRACKS m_track;
/// Objects scope
TEARDROPS_SCOPE m_scope; TEARDROPS_SCOPE m_scope;
/// Teardrops type
TEARDROPS_TYPE m_type; TEARDROPS_TYPE m_type;
/// Clear selection after the processing has finished
bool m_clearSelection; bool m_clearSelection;
/// Ignore DRC during processing
bool m_ignoreDrc; bool m_ignoreDrc;
} TEARDROPS_SETTINGS; } TEARDROPS_SETTINGS;
DIALOG_TEARDROPS(PCB_EDIT_FRAME *aParent, TEARDROPS_SETTINGS *settings);
DIALOG_TEARDROPS( PCB_EDIT_FRAME *aParent, TEARDROPS_SETTINGS *aSettings );
void OnModeAdd(wxCommandEvent &event);
void OnModeRemove(wxCommandEvent &event); void OnModeAdd( wxCommandEvent &aEvent );
void OnTracksAll(wxCommandEvent &event); void OnModeRemove( wxCommandEvent &aEvent );
void OnTracksSelected(wxCommandEvent &event); void OnTracksAll( wxCommandEvent &aEvent );
void OnStyleChanged(wxCommandEvent &event); void OnTracksSelected( wxCommandEvent &aEvent );
void OnClearSelection(wxCommandEvent &event); void OnStyleChanged( wxCommandEvent &aEvent );
void OnIgnoreDrc(wxCommandEvent &event); void OnClearSelection( wxCommandEvent &aEvent );
void OnScopeVias(wxCommandEvent &event); void OnIgnoreDrc( wxCommandEvent &aEvent );
void OnScopePads(wxCommandEvent &event); void OnScopeVias( wxCommandEvent &aEvent );
void OnScopePads( wxCommandEvent &aEvent );
private: private:
PCB_EDIT_FRAME *m_parent; PCB_EDIT_FRAME *m_parent;
TEARDROPS_SETTINGS *m_settings; TEARDROPS_SETTINGS *m_settings;
void InitDialogSettings(); void initDialogSettings();
void LockOptionsControls(bool state); void lockOptionsControls( bool aState );
void LockTracksControls(bool state); void lockTracksControls( bool aState );
void LockScopeControls(bool state); void lockScopeControls( bool aState );
}; };
#endif // DIALOG_TEARDROPS_H #endif // DIALOG_TEARDROPS_H
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Elphel, Inc.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "edit_teardrops.h" #include "edit_teardrops.h"
#include "class_board.h" #include "class_board.h"
#include "class_module.h" #include "class_module.h"
#include "ratsnest_data.h" #include "ratsnest_data.h"
#include "view/view.h" #include "view/view.h"
#include "common_actions.h" #include "common_actions.h"
#include "router/pns_utils.h"
#include "router/pns_router.h" #include "router/pns_router.h"
TEARDROPS_EDITOR::TEARDROPS_EDITOR() : TEARDROPS_EDITOR::TEARDROPS_EDITOR() :
TOOL_BASE(BATCH, TOOL_MANAGER::MakeToolId("pcbnew.TeardropsEditor"), "pcbnew.TeardropsEditor") TOOL_BASE( BATCH, TOOL_MANAGER::MakeToolId( "pcbnew.TeardropsEditor" ),
"pcbnew.TeardropsEditor" )
{ {
m_frame = NULL; m_frame = NULL;
m_view = NULL; m_view = NULL;
m_type = TEARDROP::TEARDROP_STRAIGHT; m_type = TEARDROP::TEARDROP_STRAIGHT;
m_strategy = DRC_COMPLY; m_strategy = DRC_COMPLY;
} }
TEARDROPS_EDITOR::~TEARDROPS_EDITOR() TEARDROPS_EDITOR::~TEARDROPS_EDITOR()
{ {
} }
void TEARDROPS_EDITOR::Reset(RESET_REASON aReason)
void TEARDROPS_EDITOR::Reset( RESET_REASON aReason )
{ {
m_frame = getEditFrame<PCB_EDIT_FRAME>(); m_frame = getEditFrame<PCB_EDIT_FRAME>();
m_view = getView(); m_view = getView();
m_type = TEARDROP::TEARDROP_STRAIGHT; m_type = TEARDROP::TEARDROP_STRAIGHT;
m_strategy = DRC_COMPLY; m_strategy = DRC_COMPLY;
} }
void TEARDROPS_EDITOR::FilterSelection(SELECTION &selection)
void TEARDROPS_EDITOR::filterSelection(SELECTION& aSelection )
{ {
EDA_ITEM *item = NULL; EDA_ITEM* item = NULL;
for( size_t i = 0; i < aSelection.items.GetCount(); i++ )
{
item = aSelection.items.GetPickedItem( i );
for (size_t i = 0; i < selection.items.GetCount(); i++) { if( (item != NULL) && (item->Type() != PCB_TRACE_T) )
item = selection.items.GetPickedItem(i); {
if ((item != NULL) && (item->Type() != PCB_TRACE_T)) { aSelection.items.RemovePicker( i );
selection.items.RemovePicker(i);
} }
} }
} }
bool TEARDROPS_EDITOR::EditTeardrops(const DIALOG_TEARDROPS::TEARDROPS_SETTINGS &settings)
bool TEARDROPS_EDITOR::EditTeardrops(const DIALOG_TEARDROPS::TEARDROPS_SETTINGS& aSettings )
{ {
bool retVal = false; bool retVal = false;
SELECTION selection = GetManager()->GetTool<SELECTION_TOOL>()->GetSelection(); SELECTION selection = GetManager()->GetTool<SELECTION_TOOL>()->GetSelection();
switch (settings.m_type) { switch( aSettings.m_type )
{
case DIALOG_TEARDROPS::TEARDROPS_TYPE_CURVED: case DIALOG_TEARDROPS::TEARDROPS_TYPE_CURVED:
m_type = TEARDROP::TEARDROP_CURVED; m_type = TEARDROP::TEARDROP_CURVED;
break; break;
default: default:
m_type = TEARDROP::TEARDROP_STRAIGHT; m_type = TEARDROP::TEARDROP_STRAIGHT;
} }
if (settings.m_ignoreDrc == true) { if( aSettings.m_ignoreDrc == true )
{
m_strategy = DRC_IGNORE; m_strategy = DRC_IGNORE;
} }
else { else
{
m_strategy = DRC_COMPLY; m_strategy = DRC_COMPLY;
} }
FilterSelection(selection); filterSelection( selection );
if (settings.m_mode == DIALOG_TEARDROPS::TEARDROPS_MODE_ADD) {
if (settings.m_track == DIALOG_TEARDROPS::TEARDROPS_TRACKS_ALL) { if( aSettings.m_mode == DIALOG_TEARDROPS::TEARDROPS_MODE_ADD )
retVal = AddToAll(settings); {
if( aSettings.m_track == DIALOG_TEARDROPS::TEARDROPS_TRACKS_ALL )
{
retVal = addToAll( aSettings );
} }
else if (settings.m_track == DIALOG_TEARDROPS::TEARDROPS_TRACKS_SELECTED) { else if( aSettings.m_track == DIALOG_TEARDROPS::TEARDROPS_TRACKS_SELECTED )
retVal = AddToSelected(selection, settings); {
retVal = addToSelected( selection, aSettings );
} }
} }
else if (settings.m_mode == DIALOG_TEARDROPS::TEARDROPS_MODE_REMOVE) { else if( aSettings.m_mode == DIALOG_TEARDROPS::TEARDROPS_MODE_REMOVE )
RemoveAll(); {
removeAll();
retVal = true; retVal = true;
} }
return retVal; return retVal;
} }
bool TEARDROPS_EDITOR::AddToAll(const DIALOG_TEARDROPS::TEARDROPS_SETTINGS &settings)
bool TEARDROPS_EDITOR::addToAll(const DIALOG_TEARDROPS::TEARDROPS_SETTINGS& aSettings )
{ {
bool added = false; bool added = false;
// Iterate through all vias and add teardrops to connected tracks // Iterate through all vias and add teardrops to connected tracks
if ((settings.m_scope & DIALOG_TEARDROPS::TEARDROPS_SCOPE_VIAS) == DIALOG_TEARDROPS::TEARDROPS_SCOPE_VIAS) { if( (aSettings.m_scope & DIALOG_TEARDROPS::TEARDROPS_SCOPE_VIAS) ==
for (VIA *via = GetFirstVia(m_frame->GetBoard()->m_Track); via != NULL; DIALOG_TEARDROPS::TEARDROPS_SCOPE_VIAS )
via = GetFirstVia(via->Next())) { {
if (IterateTracks(via) == true) { for( VIA* via = GetFirstVia( m_frame->GetBoard()->m_Track ); via != NULL;
via = GetFirstVia( via->Next() ) )
{
if( iterateTracks( via ) == true )
{
added = true; added = true;
} }
} }
} }
// Iterate through all modules and add teardrops to tracks connected to their pads // Iterate through all modules and add teardrops to tracks connected to their pads
if ((settings.m_scope & DIALOG_TEARDROPS::TEARDROPS_SCOPE_PADS) == DIALOG_TEARDROPS::TEARDROPS_SCOPE_PADS) { if( (aSettings.m_scope & DIALOG_TEARDROPS::TEARDROPS_SCOPE_PADS) ==
for (MODULE *module = m_frame->GetBoard()->m_Modules.GetFirst(); module != NULL; module = module->Next()) { DIALOG_TEARDROPS::TEARDROPS_SCOPE_PADS )
D_PAD *pad = module->Pads(); {
while (pad != NULL) { for( MODULE* module = m_frame->GetBoard()->m_Modules.GetFirst();
if ((pad->GetShape() == PAD_CIRCLE) && IterateTracks(pad) == true) { module != NULL;
added = true; module = module->Next() )
} {
pad = pad->Next(); D_PAD* pad = module->Pads();
}
while( pad != NULL )
{
if( (pad->GetShape() == PAD_CIRCLE) && iterateTracks( pad ) == true )
{
added = true;
}
pad = pad->Next();
}
} }
} }
if (added == true) { if( added == true )
m_frame->SaveCopyInUndoList(m_undoListPicker, UR_NEW); {
m_frame->SaveCopyInUndoList( m_undoListPicker, UR_NEW );
m_undoListPicker.ClearItemsList(); m_undoListPicker.ClearItemsList();
} }
return added; return added;
} }
bool TEARDROPS_EDITOR::AddToSelected(SELECTION &selection, const DIALOG_TEARDROPS::TEARDROPS_SETTINGS &settings)
bool TEARDROPS_EDITOR::addToSelected(SELECTION& aSelection,
const DIALOG_TEARDROPS::TEARDROPS_SETTINGS& aSettings )
{ {
bool retVal = false; bool retVal = false;
bool added = false; bool added = false;
int addedNum = 0; int addedNum = 0;
for (size_t i = 0; i < selection.items.GetCount(); i++) { for( size_t i = 0; i < aSelection.items.GetCount(); i++ )
TRACK *track = static_cast<TRACK *>(selection.items.GetPickedItem(i)); {
TRACK* track = static_cast<TRACK*>( aSelection.items.GetPickedItem( i ) );
TEARDROP teardropEnd; TEARDROP teardropEnd;
retVal = teardropEnd.Create(*track, ENDPOINT_END, m_type); retVal = teardropEnd.Create( *track, ENDPOINT_END, m_type );
if (retVal == true) {
added = DrawSegments(teardropEnd, *track); if( retVal == true )
if (added == true) { {
added = drawSegments( teardropEnd, *track );
if( added == true )
{
addedNum++; addedNum++;
} }
} }
TEARDROP teardropStart; TEARDROP teardropStart;
retVal = teardropStart.Create(*track, ENDPOINT_START, m_type); retVal = teardropStart.Create( *track, ENDPOINT_START, m_type );
if (retVal == true) {
added = DrawSegments(teardropStart, *track); if( retVal == true )
if (added == true) { {
added = drawSegments( teardropStart, *track );
if( added == true )
{
addedNum++; addedNum++;
} }
} }
} }
if (settings.m_clearSelection == true) {
GetManager()->RunAction(COMMON_ACTIONS::selectionClear, true); if( aSettings.m_clearSelection == true )
{
GetManager()->RunAction( COMMON_ACTIONS::selectionClear, true );
} }
if (addedNum > 0) { if( addedNum > 0 )
m_frame->SaveCopyInUndoList(m_undoListPicker, UR_NEW); {
m_frame->SaveCopyInUndoList( m_undoListPicker, UR_NEW );
m_undoListPicker.ClearItemsList(); m_undoListPicker.ClearItemsList();
} }
return added; return added;
} }
bool TEARDROPS_EDITOR::IterateTracks(const BOARD_CONNECTED_ITEM *aObject)
bool TEARDROPS_EDITOR::iterateTracks( const BOARD_CONNECTED_ITEM* aObject )
{ {
assert(aObject); assert( aObject );
bool retVal = false; bool retVal = false;
bool flagAdded = false; bool flagAdded = false;
for (size_t i = 0; i < aObject->m_TracksConnected.size(); i++) { for( size_t i = 0; i < aObject->m_TracksConnected.size(); i++ )
TRACK *track = aObject->m_TracksConnected[i]; {
STATUS_FLAGS objPosition = track->IsPointOnEnds(aObject->GetPosition()); TRACK* track = aObject->m_TracksConnected[i];
if (objPosition == STARTPOINT || objPosition == ENDPOINT) { STATUS_FLAGS objPosition = track->IsPointOnEnds( aObject->GetPosition() );
if( objPosition == STARTPOINT || objPosition == ENDPOINT )
{
ENDPOINT_T endpoint = (objPosition == STARTPOINT ? ENDPOINT_START : ENDPOINT_END); ENDPOINT_T endpoint = (objPosition == STARTPOINT ? ENDPOINT_START : ENDPOINT_END);
TEARDROP teardrop; TEARDROP teardrop;
retVal = teardrop.Create(*track, endpoint, m_type); retVal = teardrop.Create( *track, endpoint, m_type );
if (retVal == true) {
if (DrawSegments(teardrop, *track) == true && flagAdded == false) { if( retVal == true )
{
if( drawSegments( teardrop, *track ) == true && flagAdded == false )
{
flagAdded = true; flagAdded = true;
} }
} }
} }
} }
return flagAdded; return flagAdded;
} }
void TEARDROPS_EDITOR::RemoveAll()
void TEARDROPS_EDITOR::removeAll()
{ {
ITEM_PICKER picker(NULL, UR_DELETED); ITEM_PICKER picker( NULL, UR_DELETED );
TRACK *nextTrack = NULL;
TRACK* nextTrack = NULL;
bool removed = false; bool removed = false;
for (TRACK *track = m_frame->GetBoard()->m_Track.begin(); track != NULL; ) { for( TRACK* track = m_frame->GetBoard()->m_Track.begin(); track != NULL; )
{
nextTrack = track->Next(); nextTrack = track->Next();
if (track->GetState(FLAG1) == FLAG1) {
picker.SetItem(track); if( track->GetState( FLAG1 ) == FLAG1 )
m_undoListPicker.PushItem(picker); {
picker.SetItem( track );
m_undoListPicker.PushItem( picker );
removed = true; removed = true;
m_view->Remove(track); m_view->Remove( track );
m_frame->GetBoard()->Remove(track); m_frame->GetBoard()->Remove( track );
} }
track = nextTrack; track = nextTrack;
} }
m_frame->GetBoard()->GetRatsnest()->Recalculate(); m_frame->GetBoard()->GetRatsnest()->Recalculate();
if (removed == true) {
m_frame->SaveCopyInUndoList(m_undoListPicker, UR_DELETED); if( removed == true )
{
m_frame->SaveCopyInUndoList( m_undoListPicker, UR_DELETED );
m_undoListPicker.ClearItemsList(); m_undoListPicker.ClearItemsList();
} }
} }
bool TEARDROPS_EDITOR::DrawSegments(TEARDROP &teardrop, TRACK &aTrack)
bool TEARDROPS_EDITOR::drawSegments(TEARDROP& aTeardrop, TRACK& aTrack )
{ {
bool tracksAdded = true; bool tracksAdded = true;
bool proceedBuild = true; bool proceedBuild = true;
ITEM_PICKER picker(NULL, UR_NEW); ITEM_PICKER picker( NULL, UR_NEW );
PNS_NODE *world = PNS_ROUTER::GetInstance()->GetWorld(); PNS_NODE* world = PNS_ROUTER::GetInstance()->GetWorld();
BOARD *board = aTrack.GetBoard(); BOARD* board = aTrack.GetBoard();
std::vector<TRACK *> tracks; std::vector<TRACK*> tracks;
std::vector<VECTOR2I> coordinates; std::vector<VECTOR2I> coordinates;
teardrop.GetCoordinates(coordinates); aTeardrop.GetCoordinates( coordinates );
assert(coordinates.size() != 0); assert( coordinates.size() != 0 );
wxPoint currentPoint(0, 0); wxPoint currentPoint( 0, 0 );
wxPoint prevPoint(coordinates[0].x, coordinates[0].y); wxPoint prevPoint( coordinates[0].x, coordinates[0].y );
for (size_t i = 1; i < coordinates.size(); i++) { for( size_t i = 1; i < coordinates.size(); i++ )
if (m_strategy != DRC_IGNORE) { {
PNS_SEGMENT segment(SEG(coordinates[i - 1], coordinates[i]), aTrack.GetNetCode()); if( m_strategy != DRC_IGNORE )
segment.SetWidth(aTrack.GetWidth()); {
segment.SetLayers(PNS_LAYERSET(aTrack.GetLayer())); PNS_SEGMENT segment( SEG( coordinates[i - 1], coordinates[i] ), aTrack.GetNetCode() );
segment.SetParent(&aTrack); segment.SetWidth( aTrack.GetWidth() );
segment.SetLayers( PNS_LAYERSET( aTrack.GetLayer() ) );
segment.SetParent( &aTrack );
PNS_NODE::OBSTACLES obstacles; PNS_NODE::OBSTACLES obstacles;
if (world->QueryColliding(&segment, obstacles, PNS_ITEM::ANY, 1) > 0) {
// DRC violation found, the segment of a teadrop can not be place if( world->QueryColliding( &segment, obstacles, PNS_ITEM::ANY, 1 ) > 0 )
{
// DRC violation found, the segment of a teadrop can not be placed
tracksAdded = false; tracksAdded = false;
proceedBuild = false; proceedBuild = false;
break; break;
} }
} }
if (proceedBuild == true) {
TRACK *track = new TRACK(aTrack); if( proceedBuild == true )
track->SetWidth(aTrack.GetWidth()); {
track->SetLayer(aTrack.GetLayer()); TRACK* track = new TRACK( aTrack );
track->SetNetCode(aTrack.GetNetCode());
currentPoint = wxPoint(coordinates[i].x, coordinates[i].y); track->SetWidth( aTrack.GetWidth() );
track->SetStart(prevPoint); track->SetLayer( aTrack.GetLayer() );
track->SetEnd(currentPoint); track->SetNetCode( aTrack.GetNetCode() );
currentPoint = wxPoint( coordinates[i].x, coordinates[i].y );
track->SetStart( prevPoint );
track->SetEnd( currentPoint );
track->ClearFlags(); track->ClearFlags();
track->SetState(FLAG1, true); track->SetState( FLAG1, true );
tracks.push_back(track); tracks.push_back( track );
prevPoint = currentPoint; prevPoint = currentPoint;
picker.SetItem(track); picker.SetItem( track );
m_undoListPicker.PushItem(picker); m_undoListPicker.PushItem( picker );
} }
prevPoint = currentPoint; prevPoint = currentPoint;
} }
if (tracksAdded == true) {
BOOST_FOREACH(TRACK *item, tracks) { if( tracksAdded == true )
board->Add(item); {
m_view->Add(item); // The actual addition is done here
BOOST_FOREACH( TRACK * item, tracks ) {
board->Add( item );
m_view->Add( item );
} }
} }
else { else
{
// The teardrop can not be created thus delete all allocated tracks and // The teardrop can not be created thus delete all allocated tracks and
// remove them from undo list // remove them from undo list
BOOST_FOREACH(TRACK *item, tracks) { BOOST_FOREACH( TRACK * item, tracks ) {
m_undoListPicker.PopItem(); m_undoListPicker.PopItem();
delete item; delete item;
} }
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Elphel, Inc.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef TEARDROPS_EDITOR_H #ifndef TEARDROPS_EDITOR_H
#define TEARDROPS_EDITOR_H #define TEARDROPS_EDITOR_H
...@@ -7,51 +26,99 @@ ...@@ -7,51 +26,99 @@
#include "class_teardrop.h" #include "class_teardrop.h"
#include "import_export.h" #include "import_export.h"
/**
* @brief The TEARDROPS_EDITOR class
* creates actual tracks on the board in accordance with the preferences provided by
* the DIALOG_TEARDROPS class.
*/
class APIEXPORT TEARDROPS_EDITOR : public TOOL_BASE class APIEXPORT TEARDROPS_EDITOR : public TOOL_BASE
{ {
public: public:
TEARDROPS_EDITOR(); TEARDROPS_EDITOR();
~TEARDROPS_EDITOR(); ~TEARDROPS_EDITOR();
bool EditTeardrops(const DIALOG_TEARDROPS::TEARDROPS_SETTINGS &settings);
/**
* @brief Function \a EditTeardrops
* is invoked for any manupulation with the teardrops on current board.
* @param [in] aSettings contains user defined settings provided by teadrops editor dialog window
* @return bool - \a true in case teardrops were successfully created and \a false otherwise
*/
bool EditTeardrops( const DIALOG_TEARDROPS::TEARDROPS_SETTINGS& aSettings );
/// @copydoc TOOL_INTERACTIVE::Reset /// @copydoc TOOL_INTERACTIVE::Reset
void Reset(RESET_REASON aReason); void Reset( RESET_REASON aReason );
private: private:
typedef enum { /**
* The DRC_STRATEGY
* defines the strategy when DRC violation is detected during teardop creation.
*/
typedef enum
{
/// Do not violate DRC and quit teardrop building
DRC_COMPLY, DRC_COMPLY,
/// Ignore DRC and finish teardop
DRC_IGNORE, DRC_IGNORE,
/// Try to adjust the outline or size of a teardop (not implemented)
DRC_ADJUST DRC_ADJUST
} DRC_STRATEGY; } DRC_STRATEGY;
PCB_EDIT_FRAME *m_frame; PCB_EDIT_FRAME* m_frame;
KIGFX::VIEW *m_view; KIGFX::VIEW* m_view;
TEARDROP::TEARDROP_TYPE m_type; TEARDROP::TEARDROP_TYPE m_type;
PICKED_ITEMS_LIST m_undoListPicker; PICKED_ITEMS_LIST m_undoListPicker;
DRC_STRATEGY m_strategy; DRC_STRATEGY m_strategy;
/** /**
* @brief FilterSelection filters selected objects and removes all objects except tracks. * @brief Function \a filterSelection
* @param selection contains the list of currently selected objects * filters selected objects and removes all objects which can not be processed.
* @param [in,out] aSelection contains the list of currently selected objects on input and
* a list of valid for processing objects on output
*/ */
void FilterSelection(SELECTION &selection); void filterSelection( SELECTION& aSelection );
/** /**
* @brief IterateTracks creates teardrop for all tracks connected to \a aObject * @brief Function \a iterateTracks
* @param aObject is a board object a which teardrops should be created. Currently such an object can * creates teardrop(s) for all tracks connected to \a aObject.
* @param [in] aObject is a board object at which teardrops should be created. Currently such an object can
* be via or circular pad. * be via or circular pad.
* @return \a true if at least one teardrop was successfully added and \a false otherwise * @return \a true if at least one teardrop was successfully added and \a false otherwise
*/ */
bool IterateTracks(const BOARD_CONNECTED_ITEM *aObject); bool iterateTracks( const BOARD_CONNECTED_ITEM* aObject );
bool AddToAll(const DIALOG_TEARDROPS::TEARDROPS_SETTINGS &settings);
bool AddToSelected(SELECTION &selection, const DIALOG_TEARDROPS::TEARDROPS_SETTINGS &settings); /**
* @brief Function \a addToAll
* adds teardrops to all tracks on the board.
* @param [in] aSettings contains user defined settings
* @return bool - \a true in case teardops were successfully added and \a false otherwise
*/
bool addToAll( const DIALOG_TEARDROPS::TEARDROPS_SETTINGS& aSettings );
/** /**
* @brief RemoveAll removes all teardrops form board. * @brief Function \a addToSelected
* adds teardrops to selected tracks.
* @param [in] aSelection contains a filtered list of selected tracks
* @param [in] aSettings contains user defined settings
* @return bool - \a true in case teardops were successfully added and \a false otherwise
*/ */
void RemoveAll(); bool addToSelected( SELECTION& aSelection, const DIALOG_TEARDROPS::TEARDROPS_SETTINGS& aSettings );
bool DrawSegments(TEARDROP &teardrop, TRACK &track); /**
* @brief Function \a RemoveAll
* removes all teardrops form current board.
*/
void removeAll();
/**
* @brief Function \a drawSegments
* adds tracks composing a teardop to the board.
* @param [in] aTeardrop is a teardrop which should be created on the board
* @param [in] aTrack is a parent track, some of its parameters are copied to newly created
* segments
* @return bool - \a true in case all the tracks were successfully added and \a false
* otherwise
*/
bool drawSegments( TEARDROP& aTeardrop, TRACK& aTrack );
}; };
#endif // TEARDROPS_EDITOR_H #endif // TEARDROPS_EDITOR_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment