Support >180 deg arcs in schematic.

This commit is contained in:
Alex Shvartzkop 2023-08-07 04:53:08 +03:00
parent d03c3d0f6d
commit 717ee350c8
16 changed files with 117 additions and 154 deletions

View File

@ -4,7 +4,7 @@
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 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
@ -508,15 +508,10 @@ void EDA_SHAPE::CalcArcAngles( EDA_ANGLE& aStartAngle, EDA_ANGLE& aEndAngle ) co
aEndAngle = EDA_ANGLE( endRadial );
if( aEndAngle == aStartAngle )
aEndAngle = aStartAngle + ANGLE_360; // ring, not null
aEndAngle = aStartAngle + ANGLE_360; // ring, not null
if( aStartAngle > aEndAngle )
{
if( aEndAngle < ANGLE_0 )
aEndAngle.Normalize();
else
aStartAngle = aStartAngle.Normalize() - ANGLE_360;
}
while( aEndAngle < aStartAngle )
aEndAngle += ANGLE_360;
}
@ -1295,7 +1290,8 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case SHAPE_T::ARC:
{
int radius = GetRadius();
int radius = GetRadius();
EDA_ANGLE lastAngle = GetArcAngle();
// Edit state 0: drawing: place start
// Edit state 1: drawing: place end (center calculated for 90-degree subtended angle)
@ -1380,10 +1376,10 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case 2:
case 3:
// Pick the one of c1, c2 to keep arc <= 180 deg
m_arcCenter = c1; // first trial
// Pick the one of c1, c2 to keep arc on the same side
m_arcCenter = c1; // first trial
if( GetArcAngle() > ANGLE_180 )
if( ( lastAngle < ANGLE_180 ) != ( GetArcAngle() < ANGLE_180 ) )
m_arcCenter = c2;
break;
@ -1391,11 +1387,6 @@ void EDA_SHAPE::calcEdit( const VECTOR2I& aPosition )
case 4:
// Pick the one closer to the mouse position
m_arcCenter = GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ? c1 : c2;
// keep arc angle <= 180 deg
if( GetArcAngle() > ANGLE_180 )
std::swap( m_start, m_end );
break;
}
}

View File

@ -155,8 +155,8 @@ void CAIRO_GAL_BASE::arc_angles_xform_and_normalize( double& aStartAngle, double
endAngle = M_PI - endAngle;
}
// Normalize arc angles
SWAP( startAngle, >, endAngle );
while( endAngle < startAngle )
endAngle += M_PI * 2;
// now rotate arc according to the rotation transform matrix
// Remark:

View File

@ -900,8 +900,8 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius,
double startAngle = aStartAngle.AsRadians();
double endAngle = aEndAngle.AsRadians();
// Swap the angles, if start angle is greater than end angle
SWAP( startAngle, >, endAngle );
while( endAngle < startAngle )
endAngle += M_PI * 2;
const double alphaIncrement = calcAngleStep( aRadius );

View File

@ -5,7 +5,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017-2023 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
@ -669,8 +669,8 @@ void DXF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
// In DXF, arcs are drawn CCW.
// If startAngle > endAngle, it is CW. So transform it to CCW
if( startAngle > endAngle )
std::swap( startAngle, endAngle );
while( endAngle < startAngle )
endAngle += ANGLE_360;
VECTOR2D centre_device = userToDeviceCoordinates( aCenter );
double radius_device = userToDeviceSize( aRadius );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2022-2023 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
@ -883,12 +883,8 @@ void GERBER_PLOTTER::plotArc( const VECTOR2I& aCenter, const EDA_ANGLE& aStartAn
// devRelCenter is the position on arc center relative to the arc start, in Gerber coord.
VECTOR2D devRelCenter = userToDeviceCoordinates( aCenter ) - userToDeviceCoordinates( start );
fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode
if( aStartAngle < aEndAngle )
fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW
else
fprintf( m_outputFile, "G02*\n" ); // Active circular interpolation, CW
fprintf( m_outputFile, "G75*\n" ); // Multiquadrant (360 degrees) mode
fprintf( m_outputFile, "G03*\n" ); // Active circular interpolation, CCW
fprintf( m_outputFile, "X%dY%dI%dJ%dD01*\n",
KiROUND( devEnd.x ), KiROUND( devEnd.y ),

View File

@ -581,14 +581,19 @@ void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
chord_angle = std::max( m_arcMinChordDegrees, std::min( chord_angle, ANGLE_45 ) );
VECTOR2D centre_device = userToDeviceCoordinates( aCenter );
EDA_ANGLE startAngle( aStartAngle );
EDA_ANGLE endAngle( aEndAngle );
while( endAngle < startAngle )
endAngle += ANGLE_360;
EDA_ANGLE angle;
if( m_plotMirror )
angle = aStartAngle - aEndAngle;
angle = startAngle - endAngle;
else
angle = aEndAngle - aStartAngle;
angle.Normalize180();
angle = endAngle - startAngle;
// Calculate arc start point:
VECTOR2I cmap( aCenter.x + KiROUND( aRadius * aStartAngle.Cos() ),
@ -609,18 +614,6 @@ void HPGL_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
}
void HPGL_PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart,
const VECTOR2I& aEnd,
FILL_T aFill, int aWidth, int aMaxError )
{
EDA_ANGLE startAngle( aStart - aCenter );
EDA_ANGLE endAngle( aEnd - aCenter );
int radius = ( aStart - aCenter ).EuclideanNorm();
Arc( aCenter, -endAngle, -startAngle, radius, aFill, aWidth );
}
void HPGL_PLOTTER::FlashPadOval( const VECTOR2I& aPos, const VECTOR2I& aSize,
const EDA_ANGLE& aOrient, OUTLINE_MODE aTraceMode, void* aData )
{

View File

@ -302,13 +302,8 @@ void PDF_PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VE
VECTOR2I end( aEnd );
VECTOR2I pt;
if( startAngle > endAngle )
{
if( endAngle < ANGLE_0 )
endAngle.Normalize();
else
startAngle = startAngle.Normalize() - ANGLE_360;
}
while( endAngle < startAngle )
endAngle += ANGLE_360;
SetCurrentLineWidth( aWidth );
VECTOR2D pos_dev = userToDeviceCoordinates( start );
@ -361,11 +356,8 @@ void PDF_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
VECTOR2I end;
const EDA_ANGLE delta( 5, DEGREES_T ); // increment to draw circles
if( startAngle > endAngle )
{
std::swap( startAngle, endAngle );
std::swap( start, end );
}
while( endAngle < startAngle )
endAngle += ANGLE_360;
SetCurrentLineWidth( aWidth );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2020-2023 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
@ -548,7 +548,8 @@ void PS_PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VEC
EDA_ANGLE endAngle( mapCoords( end_device - center_device ) );
// userToDeviceCoordinates gets our start/ends out of order
std::swap( startAngle, endAngle );
if( !m_plotMirror )
std::swap( startAngle, endAngle );
SetCurrentLineWidth( aWidth );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 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
@ -461,8 +461,8 @@ void SVG_PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
EDA_ANGLE startAngle( aStartAngle );
EDA_ANGLE endAngle( aEndAngle );
if( startAngle > endAngle )
std::swap( startAngle, endAngle );
while( endAngle < startAngle )
endAngle += ANGLE_360;
// Calculate start point.
VECTOR2D centre_device = userToDeviceCoordinates( aCenter );

View File

@ -152,8 +152,8 @@ void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR
// Recalculate aCenter using double to be sure we will use a exact value, from aStart and aEnd
// it must be on the line passing by the middle of segment {aStart, aEnd}
// To simplify calculations, use aStart as origin in intermediate calculations
VECTOR2D center = aCenter - aStart;
VECTOR2D end = aEnd - aStart;
VECTOR2D center = aCenter - aStart;
VECTOR2D end = aEnd - aStart;
EDA_ANGLE segAngle( end );
// Rotate end and center, to make segment {aStart, aEnd} horizontal
@ -171,14 +171,6 @@ void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR
EDA_ANGLE endAngle( VECTOR2D( aEnd ) - center );
double radius = ( VECTOR2D( aStart ) - center ).EuclideanNorm();
if( startAngle > endAngle )
{
if( endAngle < ANGLE_0 )
endAngle.Normalize();
else
startAngle = startAngle.Normalize() - ANGLE_360;
}
// In old Kicad code, calls to Arc() using angles calls this function after
// swapping angles and negate them (to compensate the inverted Y axis).
// So to be compatible with Arc() calls with angles, do the same thing
@ -186,7 +178,7 @@ void PLOTTER::Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR
startAngle = -startAngle;
endAngle = -endAngle;
Arc( center, startAngle, endAngle, radius, aFill, aWidth );
Arc( aCenter, startAngle, endAngle, radius, aFill, aWidth );
}
@ -199,8 +191,8 @@ void PLOTTER::Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
VECTOR2I start, end;
const int sign = -1;
if( startAngle > endAngle )
std::swap( startAngle, endAngle );
while( endAngle < startAngle )
endAngle += ANGLE_360;
SetCurrentLineWidth( aWidth );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2004-2023 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
@ -139,7 +139,6 @@ void LIB_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOffs
VECTOR2I start = aTransform.TransformCoordinate( m_start ) + aOffset;
VECTOR2I end = aTransform.TransformCoordinate( m_end ) + aOffset;
VECTOR2I center = aTransform.TransformCoordinate( getCenter() ) + aOffset;
static std::vector<VECTOR2I> cornerList;
@ -158,21 +157,6 @@ void LIB_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOffs
for( const VECTOR2I& pt : m_bezierPoints )
cornerList.push_back( aTransform.TransformCoordinate( pt ) + aOffset );
}
else if( GetShape() == SHAPE_T::ARC )
{
EDA_ANGLE t1, t2;
CalcArcAngles( t1, t2 );
// N.B. The order of evaluation is critical here as MapAngles will modify t1, t2
// and the Normalize routine depends on these modifications for the correct output
bool transformed = aTransform.MapAngles( &t1, &t2 );
EDA_ANGLE arc_angle = ( t1 - t2 ).Normalize180();
bool transformed2 = ( arc_angle > ANGLE_0 ) && ( arc_angle < ANGLE_180 );
if( transformed != transformed2 )
std::swap( start, end );
}
int penWidth;
COLOR4D color = GetStroke().GetColor();
@ -241,13 +225,24 @@ void LIB_SHAPE::Plot( PLOTTER* aPlotter, bool aBackground, const VECTOR2I& aOffs
// In some plotters (not all) the arc is approximated by segments, and
// a error max is needed. We try to approximate by 360/5 segments by 360 deg
int arc2segment_error = CircleToEndSegmentDeltaRadius( GetRadius(), 360/5 );
aPlotter->Arc( center, start, end, fill, penWidth, arc2segment_error );
}
VECTOR2I mid = aTransform.TransformCoordinate( GetArcMid() ) + aOffset;
VECTOR2I center = CalcArcCenter( start, mid, end );
EDA_ANGLE startAngle = EDA_ANGLE( start - center );
EDA_ANGLE endAngle = EDA_ANGLE( end - center );
aPlotter->Arc( center, -startAngle, -endAngle, GetRadius(), fill, penWidth );
break;
}
case SHAPE_T::CIRCLE:
{
VECTOR2I center = aTransform.TransformCoordinate( getCenter() ) + aOffset;
aPlotter->Circle( center, GetRadius() * 2, fill, penWidth );
break;
}
case SHAPE_T::RECTANGLE:
aPlotter->Rect( start, end, fill, penWidth );

View File

@ -890,14 +890,17 @@ void SCH_PAINTER::draw( const LIB_SHAPE* aShape, int aLayer, bool aDimmed )
{
case SHAPE_T::ARC:
{
EDA_ANGLE startAngle;
EDA_ANGLE endAngle;
shape->CalcArcAngles( startAngle, endAngle );
VECTOR2I start = mapCoords( shape->GetStart() );
VECTOR2I mid = mapCoords( shape->GetArcMid() );
VECTOR2I end = mapCoords( shape->GetEnd() );
VECTOR2I center = CalcArcCenter( start, mid, end );
TRANSFORM().MapAngles( &startAngle, &endAngle );
EDA_ANGLE startAngle = EDA_ANGLE( start - center );
EDA_ANGLE endAngle = EDA_ANGLE( end - center );
m_gal->DrawArc( mapCoords( shape->GetCenter() ), shape->GetRadius(),
startAngle, endAngle );
std::swap( startAngle, endAngle );
m_gal->DrawArc( center, shape->GetRadius(), startAngle, endAngle );
}
break;

View File

@ -1089,34 +1089,35 @@ LIB_SHAPE* SCH_SEXPR_PARSER::parseArc()
{
arc->SetArcGeometry( startPoint, midPoint, endPoint );
#if 1
// Should be not required. Unfortunately it is needed because some bugs created
// incorrect data after conversion of old libraries to the new arc format using
// startPoint, midPoint, endPoint
// Until now, in Eeschema the arc angle should be <= 180 deg.
// If > 180 (bug...) we need to swap arc ends.
// However arc angle == 180 deg can also create issues in some cases (plotters, hittest)
// so also avoid arc == 180 deg
EDA_ANGLE arc_start, arc_end, arc_angle;
arc->CalcArcAngles( arc_start, arc_end );
arc_angle = arc_end - arc_start;
if( m_requiredVersion <= 20230121 ) // Versions before 7.0
{
// Should be not required. Unfortunately it is needed because some bugs created
// incorrect data after conversion of old libraries to the new arc format using
// startPoint, midPoint, endPoint
// Until now, in Eeschema the arc angle should be <= 180 deg.
// If > 180 (bug...) we need to swap arc ends.
// However arc angle == 180 deg can also create issues in some cases (plotters, hittest)
// so also avoid arc == 180 deg
EDA_ANGLE arc_start, arc_end, arc_angle;
arc->CalcArcAngles( arc_start, arc_end );
arc_angle = arc_end - arc_start;
if( arc_angle > ANGLE_180 )
{
// Change arc to its complement (360deg - arc_angle)
arc->SetStart( endPoint );
arc->SetEnd( startPoint );
VECTOR2I new_center = CalcArcCenter( arc->GetStart(), arc->GetEnd(),
ANGLE_360 - arc_angle );
arc->SetCenter( new_center );
if( arc_angle > ANGLE_180 )
{
// Change arc to its complement (360deg - arc_angle)
arc->SetStart( endPoint );
arc->SetEnd( startPoint );
VECTOR2I new_center =
CalcArcCenter( arc->GetStart(), arc->GetEnd(), ANGLE_360 - arc_angle );
arc->SetCenter( new_center );
}
else if( arc_angle == ANGLE_180 )
{
VECTOR2I new_center = CalcArcCenter( arc->GetStart(), arc->GetEnd(),
EDA_ANGLE( 179.5, DEGREES_T ) );
arc->SetCenter( new_center );
}
}
else if( arc_angle == ANGLE_180 )
{
VECTOR2I new_center = CalcArcCenter( arc->GetStart(), arc->GetEnd(),
EDA_ANGLE( 179.5, DEGREES_T ) );
arc->SetCenter( new_center );
}
#endif
}
else if( hasAngles )
{

View File

@ -214,10 +214,25 @@ public:
/**
* Generic fallback: arc rendered as a polyline.
* Winding direction: clockwise in increasing X -> right, increasing Y -> down system.
*/
virtual void Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
FILL_T aFill, int aWidth, int aMaxError );
/**
* Generic fallback: arc rendered as a polyline.
* Note also aCentre and aRadius are double to avoid creating rounding issues due
* to the fact a arc is defined in Kicad by a start point, a end point and third point
* not angles and radius.
* In some plotters (i.e. dxf) whe need a good precision when calculating an arc
* without error introduced by rounding, to avoid moving the end points,
* usually important in outlines when plotting an arc given by center, radius and angles.
* Winding direction: counter-clockwise in increasing X -> right, increasing Y -> down system.
*/
virtual void Arc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH );
/**
* Generic fallback: Cubic Bezier curve rendered as a polyline
* In KiCad the bezier curves have 4 control points:
@ -544,19 +559,6 @@ public:
protected:
/**
* Generic fallback: arc rendered as a polyline.
* Note also aCentre and aRadius are double to avoid creating rounding issues due
* to the fact a arc is defined in Kicad by a start point, a end point and third point
* not angles and radius.
* In some plotters (i.e. dxf) whe need a good precision when calculating an arc
* without error introduced by rounding, to avoid moving the end points,
* usually important in outlines when plotting an arc given by center, radius and angles
*/
virtual void Arc( const VECTOR2D& aCentre, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH );
virtual void ThickArc( const VECTOR2D& aCentre, const EDA_ANGLE& StAngle,
const EDA_ANGLE& EndAngle, double aRadius, int aWidth,
OUTLINE_MODE aTraceMode, void* aData );

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-2023 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
@ -106,9 +106,6 @@ public:
virtual void ThickSegment( const VECTOR2I& start, const VECTOR2I& end, int width,
OUTLINE_MODE tracemode, void* aData ) override;
virtual void Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
FILL_T aFill, int aWidth, int aMaxError ) override;
virtual void PenTo( const VECTOR2I& pos, char plume ) override;
virtual void FlashPadCircle( const VECTOR2I& aPadPos, int aDiameter,

View File

@ -329,6 +329,10 @@ public:
virtual void Arc( const VECTOR2I& aCenter, const VECTOR2I& aStart, const VECTOR2I& aEnd,
FILL_T aFill, int aWidth, int aMaxError ) override;
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
/**
* Polygon plotting for PDF. Everything is supported
*/
@ -415,10 +419,6 @@ protected:
OUTLINE_NODE* addOutlineNode( OUTLINE_NODE* aParent, int aActionHandle,
const wxString& aTitle );
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius,
FILL_T aFill, int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
/// convert a wxString unicode string to a char string compatible with the accepted
/// string PDF format (convert special chars and non ascii7 chars)
std::string encodeStringForPlotter( const wxString& aUnicode ) override;
@ -555,6 +555,10 @@ public:
virtual void Circle( const VECTOR2I& pos, int diametre, FILL_T fill,
int width = USE_DEFAULT_LINE_WIDTH ) override;
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius, FILL_T aFill,
int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
virtual void BezierCurve( const VECTOR2I& aStart, const VECTOR2I& aControl1,
const VECTOR2I& aControl2, const VECTOR2I& aEnd,
int aTolerance,
@ -622,10 +626,6 @@ public:
void* aData = nullptr ) override;
protected:
virtual void Arc( const VECTOR2D& aCenter, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aEndAngle, double aRadius,
FILL_T aFill, int aWidth = USE_DEFAULT_LINE_WIDTH ) override;
/**
* Initialize m_pen_rgb_color from reduced values r, g ,b
* ( reduced values are 0.0 to 1.0 )