/* @file DrawingLinePath.java * * @author marco corvi * @date nov 2011 * * @brief TopoDroid drawing: line-path (lines) * * The line path id DrawingPath.mPath * * -------------------------------------------------------- * Copyright This sowftare is distributed under GPL-3.0 or later * See the file COPYING. * -------------------------------------------------------- */ package com.topodroid.DistoX; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Matrix; import java.io.PrintWriter; import java.io.StringWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Iterator; // import java.util.List; import java.util.ArrayList; import java.util.Locale; import android.util.Log; /** */ public class DrawingLinePath extends DrawingPointLinePath { static final int OUTLINE_OUT = 1; static final int OUTLINE_IN = -1; static final int OUTLINE_NONE = 0; static final int OUTLINE_UNDEF = -2; boolean hasOutline() { return mOutline == OUTLINE_OUT || mOutline == OUTLINE_IN; } // static int mCount = 0; // int mCnt; int mLineType; int mOutline; private boolean mReversed; public DrawingLinePath( int line_type ) { // visible = true, closed = false super( DrawingPath.DRAWING_PATH_LINE, true, false ); // BrushManager.makePaths( ); // mCnt = ++ mCount; // TDLog.Log( TDLog.LOG_PATH, "DrawingLinePath " + mCnt + " cstr type " + line_type ); mLineType = line_type; mReversed = false; mOutline = ( mLineType == BrushManager.mLineLib.mLineWallIndex )? OUTLINE_OUT : OUTLINE_NONE; setPaint( BrushManager.mLineLib.getLinePaint( mLineType, mReversed ) ); } static DrawingLinePath loadDataStream( int version, DataInputStream dis, float x, float y, SymbolsPalette missingSymbols ) { int type; boolean closed, reversed; int outline; String fname, options; try { fname = dis.readUTF(); closed = (dis.read() == 1); // visible= (dis.read() == 1); reversed = (dis.read() == 1); outline = dis.readInt(); options = dis.readUTF(); // BrushManager.mLineLib.tryLoadMissingArea( fname ); type = BrushManager.mLineLib.getSymbolIndexByFilename( fname ); if ( type < 0 ) { if ( missingSymbols != null ) missingSymbols.addLineFilename( fname ); type = 0; } DrawingLinePath ret = new DrawingLinePath( type ); ret.mOutline = outline; ret.mOptions = options; ret.setReversed( reversed ); int npt = dis.readInt(); // TDLog.Log( TDLog.LOG_PLOT, "L: " + fname + " T " + type + " R" + reversed + " C" + closed + " NP " + npt ); int has_cp; float mX1, mY1, mX2, mY2, mX, mY; mX = x + dis.readFloat(); mY = y + dis.readFloat(); has_cp = dis.read(); // this is 0 if ( has_cp == 1 ) { // consume 4 floats mX1 = x + dis.readFloat(); mY1 = y + dis.readFloat(); mX2 = x + dis.readFloat(); mY2 = y + dis.readFloat(); } ret.addStartPointNoPath( mX, mY ); for ( int k=1; k<npt; ++k ) { mX = x + dis.readFloat(); mY = y + dis.readFloat(); has_cp = dis.read(); if ( has_cp == 1 ) { mX1 = x + dis.readFloat(); mY1 = y + dis.readFloat(); mX2 = x + dis.readFloat(); mY2 = y + dis.readFloat(); ret.addPoint3NoPath( mX1, mY1, mX2, mY2, mX, mY ); } else { ret.addPointNoPath( mX, mY ); } } if ( closed ) { ret.setClosed( closed ); ret.close(); } ret.retracePath(); return ret; } catch ( IOException e ) { TDLog.Error( "LINE in error " + e.getMessage() ); // Log.v("DistoX", "LINE in error " + e.getMessage() ); } return null; } @Override void computeUnitNormal() { mDx = mDy = 0; if ( mFirst != null && mFirst.mNext != null ) { LinePoint second = mFirst.mNext; mDx = second.mY - mFirst.mY; mDy = - second.mX + mFirst.mX; float d = ( mDx*mDx + mDy*mDy ); if ( d > 0 ) { d = 1 / (float)Math.sqrt( d ); if ( mReversed ) d = -d; mDx *= d; mDy *= d; } } } /** * @param exclude whether to exclude splitting-point */ boolean splitAt( LinePoint lp0, DrawingLinePath line1, DrawingLinePath line2, boolean exclude ) // x,y scene point { line1.mOutline = mOutline; line1.mOptions = mOptions; line1.mReversed = mReversed; line2.mOutline = mOutline; line2.mOptions = mOptions; line2.mReversed = mReversed; // int k0 = mPoints.indexOf( lp0 ); // int kmax = mPoints.size() - 1; // if ( k0 <= 0 || k0 >= kmax ) return false; if ( lp0 == mFirst || lp0 == mLast ) return false; if ( exclude ) { // if ( k0 <= 1 || k0 >= kmax-1 ) return false; if ( lp0 == mFirst.mNext || lp0 == mLast.mPrev ) return false; } // LinePoint lp = mPoints.get( 0 ); LinePoint lp = mFirst; line1.addStartPoint( lp.mX, lp.mY ); // int k; // for ( k=1; k<k0; ++ k ) for ( lp=lp.mNext; lp != lp0 && lp != null; lp = lp.mNext ) { // lp = mPoints.get(k); if ( lp.has_cp ) { line1.addPoint3( lp.mX1, lp.mY1, lp.mX2, lp.mY2, lp.mX, lp.mY ); } else { line1.addPoint( lp.mX, lp.mY ); } } if ( ! exclude ) { // lp = mPoints.get(k); // k == k0 if ( lp.has_cp ) { line1.addPoint3( lp.mX1, lp.mY1, lp.mX2, lp.mY2, lp.mX, lp.mY ); } else { line1.addPoint( lp.mX, lp.mY ); } } else { // ++ k; // lp = mPoints.get(k); // k == k0+1 if ( lp != null ) { lp = lp.mNext; } } if ( lp != null ) { line2.addStartPoint( lp.mX, lp.mY ); // for ( ++k; k < mPoints.size(); ++k ) for ( lp=lp.mNext; lp != null; lp = lp.mNext ) { // lp = mPoints.get(k); if ( lp.has_cp ) { line2.addPoint3( lp.mX1, lp.mY1, lp.mX2, lp.mY2, lp.mX, lp.mY ); } else { line2.addPoint( lp.mX, lp.mY ); } } } // Log.v( TopoDroidApp.TAG, "line " + mCnt + " split: " + size() + " --> " + line1.size() + " + " + line2.size() ); line1.computeUnitNormal(); line2.computeUnitNormal(); return true; } void setReversed( boolean reversed ) { if ( reversed != mReversed ) { mReversed = reversed; // retracePath(); setPaint( BrushManager.mLineLib.getLinePaint( mLineType, mReversed ) ); computeUnitNormal(); } } void flipReversed() { mReversed = ! mReversed; // retracePath(); setPaint( BrushManager.mLineLib.getLinePaint( mLineType, mReversed ) ); computeUnitNormal(); } boolean isReversed() { return mReversed; } public int lineType() { return mLineType; } void setLineType( int type ) { mLineType = type; setPaint( BrushManager.mLineLib.getLinePaint( mLineType, mReversed ) ); } @Override public void toCsurvey( PrintWriter pw, String cave, String branch ) { int layer = BrushManager.getLineCsxLayer( mLineType ); int type = BrushManager.getLineCsxType( mLineType ); int cat = BrushManager.getLineCsxCategory( mLineType ); int pen = BrushManager.getLineCsxPen( mLineType ); // linetype: 0 line, 1 spline, 2 bezier pw.format(" <item layer=\"%d\" cave=\"%s\" branch=\"%s\" name=\"\" type=\"%d\" category=\"%d\" linetype=\"0\" mergemode=\"0\">\n", layer, cave, branch, type, cat ); pw.format(" <pen type=\"%d\" />\n", pen); pw.format(" <points data=\""); boolean b = true; // for ( LinePoint pt : mPoints ) if ( ! mReversed ) { // NOTE do not skip tick-point if want to save section with tick // if ( mLineType == BrushManager.mLineLib.mLineSectionIndex && size() > 2 ) pt = pt.mNext; // skip first point (tick) LinePoint pt = mFirst; for ( ; pt != null; pt = pt.mNext ) { float x = DrawingUtil.sceneToWorldX( pt.mX ); float y = DrawingUtil.sceneToWorldY( pt.mY ); pw.format(Locale.US, "%.2f %.2f ", x, y ); if ( b ) { pw.format("B "); b = false; } } } else { LinePoint pt = mLast; for ( ; pt != null; pt = pt.mPrev ) { float x = DrawingUtil.sceneToWorldX( pt.mX ); float y = DrawingUtil.sceneToWorldY( pt.mY ); pw.format(Locale.US, "%.2f %.2f ", x, y ); if ( b ) { pw.format("B "); b = false; } } } pw.format("\" />\n"); pw.format(" </item>\n"); } @Override public String toTherion() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.format("line %s", BrushManager.mLineLib.getSymbolThName(mLineType) ); if ( isClosed() ) { pw.format(" -close on"); } if ( mLineType == BrushManager.mLineLib.mLineWallIndex ) { if ( mOutline == OUTLINE_IN ) { pw.format(" -outline in"); } else if ( mOutline == OUTLINE_NONE ) { pw.format(" -outline none"); } } else { if ( mOutline == OUTLINE_IN ) { pw.format(" -outline in"); } else if ( mOutline == OUTLINE_OUT ) { pw.format(" -outline out"); } } if ( mReversed ) { pw.format(" -reverse on"); } if ( mOptions != null && mOptions.length() > 0 ) { pw.format(" %s", mOptions ); } pw.format("\n"); // for ( LinePoint pt : mPoints ) LinePoint pt = mFirst; // if ( mLineType == BrushManager.mLineLib.mLineSectionIndex && size() > 2 ) pt = pt.mNext; // skip first point (tick) for ( ; pt != null; pt = pt.mNext ) { pt.toTherion( pw ); } if ( mLineType == BrushManager.mLineLib.mLineSlopeIndex ) { pw.format(" l-size 40\n"); } pw.format("endline\n"); return sw.getBuffer().toString(); } @Override void toDataStream( DataOutputStream dos ) { String name = BrushManager.mLineLib.getSymbolThName( mLineType ); try { dos.write( 'L' ); dos.writeUTF( name ); dos.write( isClosed()? 1 : 0 ); // dos.write( isVisible()? 1 : 0 ); dos.write( mReversed? 1 : 0 ); dos.writeInt( mOutline ); dos.writeUTF( ( mOptions != null )? mOptions : "" ); int npt = size(); // number of line points dos.writeInt( npt ); for ( LinePoint pt = mFirst; pt != null; pt = pt.mNext ) { pt.toDataStream( dos ); } // TDLog.Log( TDLog.LOG_PLOT, "L " + name + " " + npt ); } catch ( IOException e ) { TDLog.Error( "LINE out error " + e.toString() ); } } }