rs274_read_XY_and_IJ_coordinates.cpp 8.61 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2010-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
 * Copyright (C) 1992-2014 KiCad Developers, see change_log.txt for contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
24

25 26
#include <fctsys.h>
#include <common.h>
27

28 29 30
#include <gerbview.h>
#include <macros.h>
#include <class_GERBER.h>
31
#include <base_units.h>
32 33 34


/* These routines read the text string point from Text.
35
 * On exit, Text points the beginning of the sequence unread
36
 */
37 38 39 40 41

// convertion scale from gerber file units to Gerbview internal units
// depending on the gerber file format
// this scale list assumes gerber units are imperial.
// for metric gerber units, the imperial to metric conversion is made in read functions
42
#define SCALE_LIST_SIZE 9
43
static double scale_list[SCALE_LIST_SIZE] =
44
{
45 46 47 48 49 50
    1000.0 * IU_PER_MILS,   // x.1 format (certainly useless)
    100.0 * IU_PER_MILS,    // x.2 format (certainly useless)
    10.0 * IU_PER_MILS,     // x.3 format
    1.0 * IU_PER_MILS,      // x.4 format
    0.1 * IU_PER_MILS,      // x.5 format
    0.01 * IU_PER_MILS,     // x.6 format
51 52
    0.001 * IU_PER_MILS,     // x.7 format  (currently the max allowed precision)
    0.0001 * IU_PER_MILS,   // provided, but not used
53
    0.00001 * IU_PER_MILS,  // provided, but not used
54 55
};

56
/*
57
 * Function scale
58 59
 * converts a coordinate given in floating point to Gerbvies internal units
 * (currently = 10 nanometers)
60 61 62 63 64
 */
int scaletoIU( double aCoord, bool isMetric )
{
    int ret;

65 66 67
    if( isMetric )  // gerber are units in mm
        ret = KiROUND( aCoord * IU_PER_MM );
    else            // gerber are units in inches
68
        ret = KiROUND( aCoord * IU_PER_MILS * 1000.0 );
69 70 71 72 73

    return ret;
}


74
wxPoint GERBER_IMAGE::ReadXYCoord( char*& Text )
75 76 77
{
    wxPoint pos;
    int     type_coord = 0, current_coord, nbdigits;
78
    bool    is_float   = m_DecimalFormat;
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    char*   text;
    char    line[256];


    if( m_Relative )
        pos.x = pos.y = 0;
    else
        pos = m_CurrentPos;

    if( Text == NULL )
        return pos;

    text = line;
    while( *Text )
    {
        if( (*Text == 'X') || (*Text == 'Y') )
        {
            type_coord = *Text;
            Text++;
            text     = line;
            nbdigits = 0;
100

101 102
            while( IsNumber( *Text ) )
            {
103
                if( *Text == '.' )  // Force decimat format if reading a floating point number
104 105 106 107 108 109 110 111 112
                    is_float = true;

                // count digits only (sign and decimal point are not counted)
                if( (*Text >= '0') && (*Text <='9') )
                    nbdigits++;
                *(text++) = *(Text++);
            }

            *text = 0;
113

114 115
            if( is_float )
            {
116 117
                // When X or Y values are float numbers, they are given in mm or inches
                if( m_GerbMetric )  // units are mm
118
                    current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
119
                else    // units are inches
120
                    current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
121 122 123 124
            }
            else
            {
                int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
125

126 127 128 129 130 131 132 133 134 135 136 137
                if( m_NoTrailingZeros )
                {
                    int min_digit =
                        (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
                    while( nbdigits < min_digit )
                    {
                        *(text++) = '0';
                        nbdigits++;
                    }

                    *text = 0;
                }
138

139
                current_coord = atoi( line );
140
                double real_scale = scale_list[fmt_scale];
141 142 143 144

                if( m_GerbMetric )
                    real_scale = real_scale / 25.4;

145
                current_coord = KiROUND( current_coord * real_scale );
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
            }

            if( type_coord == 'X' )
                pos.x = current_coord;
            else if( type_coord == 'Y' )
                pos.y = current_coord;

            continue;
        }
        else
            break;
    }

    if( m_Relative )
    {
        pos.x += m_CurrentPos.x;
        pos.y += m_CurrentPos.y;
    }

    m_CurrentPos = pos;
    return pos;
}


/* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
 * These coordinates are relative, so if coordinate is absent, it's value
 * defaults to 0
 */
174
wxPoint GERBER_IMAGE::ReadIJCoord( char*& Text )
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
{
    wxPoint pos( 0, 0 );

    int     type_coord = 0, current_coord, nbdigits;
    bool    is_float   = false;
    char*   text;
    char    line[256];

    if( Text == NULL )
        return pos;

    text = line;
    while( *Text )
    {
        if( (*Text == 'I') || (*Text == 'J') )
        {
            type_coord = *Text;
            Text++;
            text     = line;
            nbdigits = 0;
            while( IsNumber( *Text ) )
            {
                if( *Text == '.' )
                    is_float = true;

                // count digits only (sign and decimal point are not counted)
                if( (*Text >= '0') && (*Text <='9') )
                    nbdigits++;
203

204 205 206 207 208 209
                *(text++) = *(Text++);
            }

            *text = 0;
            if( is_float )
            {
210 211
                // When X or Y values are float numbers, they are given in mm or inches
                if( m_GerbMetric )  // units are mm
212
                    current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
213
                else    // units are inches
214
                    current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
215 216 217 218 219
            }
            else
            {
                int fmt_scale =
                    (type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
220

221 222 223 224 225 226 227 228 229 230 231 232
                if( m_NoTrailingZeros )
                {
                    int min_digit =
                        (type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
                    while( nbdigits < min_digit )
                    {
                        *(text++) = '0';
                        nbdigits++;
                    }

                    *text = 0;
                }
233

234
                current_coord = atoi( line );
235

236
                double real_scale = scale_list[fmt_scale];
237

238 239
                if( m_GerbMetric )
                    real_scale = real_scale / 25.4;
240

241
                current_coord = KiROUND( current_coord * real_scale );
242 243 244 245 246
            }
            if( type_coord == 'I' )
                pos.x = current_coord;
            else if( type_coord == 'J' )
                pos.y = current_coord;
247

248 249 250 251 252 253 254 255 256
            continue;
        }
        else
            break;
    }

    m_IJPos = pos;
    return pos;
}
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274


// Helper functions:

/**
 * Function ReadInt
 * reads an int from an ASCII character buffer.  If there is a comma after the
 * int, then skip over that.
 * @param text A reference to a character pointer from which bytes are read
 *    and the pointer is advanced for each byte read.
 * @param aSkipSeparator = true (default) to skip comma
 * @return int - The int read in.
 */
int ReadInt( char*& text, bool aSkipSeparator = true )
{
    int ret = (int) strtol( text, &text, 10 );

    if( *text == ',' || isspace( *text ) )
275
    {
276 277
        if( aSkipSeparator )
            ++text;
278
    }
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297

    return ret;
}


/**
 * Function ReadDouble
 * reads a double from an ASCII character buffer. If there is a comma after
 * the double, then skip over that.
 * @param text A reference to a character pointer from which the ASCII double
 *          is read from and the pointer advanced for each character read.
 * @param aSkipSeparator = true (default) to skip comma
 * @return double
 */
double ReadDouble( char*& text, bool aSkipSeparator = true )
{
    double ret = strtod( text, &text );

    if( *text == ',' || isspace( *text ) )
298
    {
299 300
        if( aSkipSeparator )
            ++text;
301
    }
302 303 304 305

    return ret;
}