/** @file SymbolArea.java
*
* @author marco corvi
* @date dec 2012
*
* @brief TopoDroid drawing: area symbol
* --------------------------------------------------------
* Copyright This sowftare is distributed under GPL-3.0 or later
* See the file COPYING.
* --------------------------------------------------------
*/
package com.topodroid.DistoX;
import java.io.File;
import java.io.FileReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Shader.TileMode;
import android.util.Log;
class SymbolArea extends Symbol
{
String mName;
int mColor;
boolean mCloseHorizontal;
boolean mOrientable;
// FIXME AREA_ORIENT
double mOrientation;
Paint mPaint;
Path mPath;
Bitmap mBitmap;
Bitmap mShaderBitmap = null;
BitmapShader mShader; // paint bitmap shader
TileMode mXMode;
TileMode mYMode;
@Override public String getName() { return mName; }
@Override public String getThName( ) { return mThName; }
@Override public Paint getPaint() { return mPaint; }
@Override public Path getPath() { return mPath; }
@Override public boolean isOrientable() { return mOrientable; }
// @Override public boolean isEnabled() { return mEnabled; }
// @Override public void setEnabled( boolean enabled ) { mEnabled = enabled; }
// @Override public void toggleEnabled() { mEnabled = ! mEnabled; }
// FIXME AREA_ORIENT
@Override public boolean setAngle( float angle )
{
if ( mBitmap == null ) return false;
mOrientation = angle;
// TDLog.Error( "ERROR area symbol set orientation " + angle + " not supported" );
android.graphics.Matrix m = new android.graphics.Matrix();
m.preRotate( (float)mOrientation );
mShader.setLocalMatrix( m );
return true;
}
// FIXME AREA_ORIENT
@Override public int getAngle() { return (int)mOrientation; }
/**
* color 0xaarrggbb
*/
SymbolArea( String name, String th_name, String fname, int color, Bitmap bitmap, TileMode xmode, TileMode ymode,
boolean close_horizontal )
{
super( th_name, fname );
mName = name;
mColor = color;
mBitmap = bitmap;
mXMode = xmode;
mYMode = ymode;
mCloseHorizontal = close_horizontal;
mOrientable = false;
// FIXME AREA_ORIET mOrientation = 0;
mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor( mColor );
mPaint.setAlpha( 0x66 );
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth( TDSetting.mLineThickness );
makeShader( mBitmap, mXMode, mYMode, true );
makePath();
}
// FIXME AREA_ORIENT
void rotateGradArea( double a )
{
if ( mOrientable ) {
// TDLog.Error( "ERROR area symbol rotate by " + a + " not implementd" );
mOrientation += a;
while ( mOrientation >= 360 ) mOrientation -= 360;
while ( mOrientation < 0 ) mOrientation += 360;
if ( mShader != null ) {
android.graphics.Matrix m = new android.graphics.Matrix();
m.preRotate( (float)mOrientation );
mShader.setLocalMatrix( m );
}
}
}
void makePath()
{
mPath = new Path();
if ( mCloseHorizontal ) {
mPath.moveTo( -10, -5 );
mPath.cubicTo( -10, 0, -5, 5, 0, 5 );
mPath.cubicTo( 5, 5, 10, 0, 10, -5 );
mPath.close();
} else {
mPath.addCircle( 0, 0, 10, Path.Direction.CCW );
}
}
SymbolArea( String filepath, String fname, String locale, String iso )
{
super( null, fname );
mOrientable = false;
// FIXME AREA_ORIENT
mOrientation = 0;
readFile( filepath, locale, iso );
makePath();
}
private Bitmap makeBitmap( int[] pxl, int w1, int h1 )
{
if ( w1 > 0 && h1 > 0 ) {
int w2 = w1 * 2;
int h2 = h1 * 2;
int pxl2[] = new int[ w2 * h2 ];
for ( int j=0; j<h1; ++j ) {
for ( int i=0; i < w1; ++i ) {
pxl2[j*w2+i] = pxl2[j*w2+i+w1] = pxl2[(j+h1)*w2+i] = pxl2[(j+h1)*w2+i+w1] = pxl[j*w1+i];
}
}
Bitmap bitmap = Bitmap.createBitmap( w2, h2, Bitmap.Config.ARGB_8888 );
bitmap.setPixels( pxl2, 0, w2, 0, 0, w2, h2 );
// bitmap.setPixels( pxl, 0, width, width, 0, width, height );
// bitmap.setPixels( pxl, 0, width, 0, height, width, height );
// bitmap.setPixels( pxl, 0, width, width, height, width, height );
return bitmap;
}
return null;
}
private void makeShader( Bitmap bitmap0, TileMode xmode, TileMode ymode, boolean subimage )
{
if ( bitmap0 == null ) return;
Bitmap bitmap = bitmap0;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if ( width > 0 && height > 0 ) {
if ( subimage ) {
int w1 = width / 2;
int h1 = height / 2;
mShaderBitmap = Bitmap.createBitmap( bitmap0, w1/2, h1/2, w1, h1 );
}
mShader = new BitmapShader( mShaderBitmap, xmode, ymode );
mPaint.setShader( mShader );
}
}
/** create a symbol reading it from a file
* The file syntax is
* symbol area
* name NAME
* th_name THERION_NAME
* color 0xHHHHHH_COLOR 0xAA_ALPHA
* endsymbol
*/
void readFile( String filename, String locale, String iso )
{
// Log.v( TopoDroidApp.TAG, "SymbolPoint::readFile " + filename + " " + locale + " " + iso );
String name = null;
String th_name = null;
int color = 0;
int alpha = 0x66;
mBitmap = null;
int width = 0;
int height = 0;
mXMode = TileMode.REPEAT;
mYMode = TileMode.REPEAT;
int pxl[] = null;
try {
// FileReader fr = new FileReader( filename );
FileInputStream fr = new FileInputStream( filename );
BufferedReader br = new BufferedReader( new InputStreamReader( fr, iso ) );
String line;
line = br.readLine();
while ( line != null ) {
line.trim();
String[] vals = line.split(" ");
int s = vals.length;
for (int k=0; k<s; ++k ) {
if ( vals[k].startsWith( "#" ) ) break;
if ( vals[k].length() == 0 ) continue;
if ( vals[k].equals("symbol") ) {
name = null;
th_name = null;
mColor = 0x00000000;
} else if ( vals[k].equals("name") || vals[k].equals(locale) ) {
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
// Log.v( TopoDroidApp.TAG, "found name " + vals[k] );
name = (new String( vals[k].getBytes(iso) )).replace("_", " ");
}
} else if ( vals[k].equals("th_name") ) {
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
th_name = vals[k];
}
} else if ( vals[k].equals("csurvey") ) {
// csurvey <layer> <category> <pen_type> <brush_type>
try {
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
mCsxLayer = Integer.parseInt( vals[k] );
}
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
mCsxCategory = Integer.parseInt( vals[k] );
}
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
mCsxPen = Integer.parseInt( vals[k] );
}
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
mCsxBrush = Integer.parseInt( vals[k] );
}
} catch ( NumberFormatException e ) {
TDLog.Error( filename + " parse error: " + line );
}
} else if ( vals[k].equals("color") ) {
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
color = Integer.decode( vals[k] );
}
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
alpha = Integer.decode( vals[k] );
}
} else if ( vals[k].equals("bitmap") ) {
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
try {
width = Integer.parseInt( vals[k] );
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
height = Integer.parseInt( vals[k] );
mXMode = TileMode.REPEAT;
mYMode = TileMode.REPEAT;
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
if ( vals[k].equals("M") ) { mXMode = TileMode.MIRROR; }
++k; while ( k < s && vals[k].length() == 0 ) ++k;
if ( k < s ) {
if ( vals[k].equals("M") ) { mYMode = TileMode.MIRROR; }
}
}
if ( width > 0 && height > 0 ) {
pxl = new int[ width * height];
int col = (color & 0x00ffffff) | 0x33000000;
for ( int j=0; j<height; ++j ) {
for ( int i=0; i<width; ++i ) pxl[j*width+i] = col;
}
col = (color & 0x00ffffff) | ( alpha << 24 );
// Log.v("DistoX", "bitmap " + width + " " + height );
for ( int j=0; j<height; ++j ) {
line = br.readLine().trim();
// Log.v("DistoX", "bitmap line <" + line + ">" );
if ( line.startsWith("endbitmap") ) {
mBitmap = makeBitmap( pxl, width, height );
pxl = null;
break;
}
for ( int i=0; i<width && i <line.length(); ++i ) if ( line.charAt(i) == '1' ) pxl[j*width+i] = col;
}
}
}
} catch ( NumberFormatException e ) {
TDLog.Error( filename + " parse bitmap error: " + line );
}
}
} else if ( vals[k].equals("endbitmap") ) {
mBitmap = makeBitmap( pxl, width, height );
pxl = null;
} else if ( vals[k].equals("orientable") ) {
mOrientable = true;
} else if ( vals[k].equals("close-horizontal") ) {
mCloseHorizontal = true;
} else if ( vals[k].equals("endsymbol") ) {
if ( name == null ) {
} else if ( th_name == null ) {
} else {
mName = name;
mThName = th_name;
mPaint = new Paint();
mPaint.setDither(true);
mColor = (alpha << 24) | color;
mPaint.setColor( color );
mPaint.setAlpha( alpha );
// mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth( TDSetting.mLineThickness );
}
}
}
line = br.readLine();
}
} catch ( FileNotFoundException e ) {
TDLog.Error( "File not found: " + e.getMessage() );
} catch( IOException e ) {
TDLog.Error( "I/O error: " + e.getMessage() );
}
makeShader( mBitmap, mXMode, mYMode, true );
}
}