/* @file DrawingCommandManager.java
*
* @author marco corvi
* @date nov 2011
*
* @brief TopoDroid drawing: commands manager
* --------------------------------------------------------
* 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.Matrix;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.PointF;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
// import android.graphics.Path.Direction;
import android.os.Handler;
import java.util.Iterator;
import java.util.List;
// import java.util.Locale;
import java.util.Collections;
import java.util.ArrayList;
import java.io.BufferedWriter;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.FileReader;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
// import java.io.BufferedReader;
import java.io.IOException;
import java.io.EOFException;
import java.util.Locale;
import android.util.Log;
/**
*/
public class DrawingCommandManager
{
private static final int BORDER = 20;
private static final float mCloseness = TDSetting.mCloseness;
static int mDisplayMode = DisplayMode.DISPLAY_ALL;
RectF mBBox;
private DrawingPath mNorthLine;
DrawingPath mFirstReference;
DrawingPath mSecondReference;
private List<DrawingPath> mGridStack1;
private List<DrawingPath> mGridStack10;
private List<DrawingPath> mGridStack100;
List<DrawingPath> GetGrid1() { return mGridStack1; }
List<DrawingPath> GetGrid10() { return mGridStack10; }
List<DrawingPath> GetGrid100() { return mGridStack100; }
private List<DrawingPath> mLegsStack;
private List<DrawingPath> mSplaysStack;
private List<ICanvasCommand> mCurrentStack;
private List<DrawingStationPath> mUserStations; // user-inserted stations
private List<ICanvasCommand> mRedoStack;
// private List<DrawingPath> mHighlight; // highlighted path
private List<DrawingStationName> mStations; // survey stations
private int mMaxAreaIndex; // max index of areas in this plot
private Selection mSelection;
private SelectionSet mSelected;
private boolean mDisplayPoints;
private Matrix mMatrix;
private float mScale; // current zoom: value of 1 pl in scene space
DrawingPath getNorth() { return mNorthLine; }
List<DrawingPath> getLegs() { return mLegsStack; }
List<DrawingPath> getSplays() { return mSplaysStack; }
List<ICanvasCommand> getCommands() { return mCurrentStack; }
List<DrawingStationName> getStations() { return mStations; }
List<DrawingStationPath> getUserStations() { return mUserStations; }
/* Check if any line overlaps another of the same type
* In case of overlap the overlapped line is removed
*/
void checkLines()
{
synchronized( mCurrentStack ) {
int size = mCurrentStack.size();
for ( int i1 = 0; i1 < size; ++i1 ) {
ICanvasCommand cmd1 = mCurrentStack.get( i1 );
DrawingPath path1 = (DrawingPath)cmd1;
if ( path1.mType != DrawingPath.DRAWING_PATH_LINE ) continue;
DrawingLinePath line1 = (DrawingLinePath)path1;
for ( int i2 = 0; i2 < size; ++i2 ) {
if ( i2 == i1 ) continue;
ICanvasCommand cmd2 = mCurrentStack.get( i2 );
DrawingPath path2 = (DrawingPath)cmd2;
if ( path2.mType != DrawingPath.DRAWING_PATH_LINE ) continue;
DrawingLinePath line2 = (DrawingLinePath)path2;
// if every point in line2 overlaps a point in line1
if ( line1.overlap( line1 ) == line2.size() ) {
TDLog.Error("LINE OVERLAP " + i1 + "-" + i2 + " total nr. " + size );
// for ( int i=0; i<size; ++i ) {
// ICanvasCommand cmd = mCurrentStack.get( i );
// DrawingPath path = (DrawingPath)cmd;
// if ( path.mType != DrawingPath.DRAWING_PATH_LINE ) continue;
// DrawingLinePath line = (DrawingLinePath)path;
// line.dump();
// }
// Log.v("DistoX", "LINE1 ");
// line1.dump();
// Log.v("DistoX", "LINE2 ");
// line2.dump();
doDeletePath( line2 );
-- size;
-- i2;
// throw new RuntimeException();
if ( i2 < i1 ) --i1;
}
}
}
}
}
/* Flip the X-axis
* flip the drawing about the vertical direction
*/
private void flipXAxes( List<DrawingPath> paths )
{
final float z = 1/mScale;
final Iterator i1 = paths.iterator();
while ( i1.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i1.next();
drawingPath.flipXAxis( z );
}
}
void flipXAxis( float z )
{
synchronized( mGridStack1 ) {
flipXAxes( mGridStack1 );
if ( mNorthLine != null ) mNorthLine.flipXAxis(z);
flipXAxes( mGridStack10 );
flipXAxes( mGridStack100 );
}
synchronized( mLegsStack ) { flipXAxes( mLegsStack ); }
synchronized( mSplaysStack ) { flipXAxes( mSplaysStack ); }
synchronized( mStations ) {
for ( DrawingStationName st : mStations ) {
st.flipXAxis(z);
}
}
if ( mCurrentStack != null ) {
Selection selection = new Selection();
synchronized( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand cmd = (ICanvasCommand) i.next();
if ( cmd.commandType() == 0 ) {
cmd.flipXAxis(z);
DrawingPath path = (DrawingPath)cmd;
if ( path.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath line = (DrawingLinePath)path;
line.flipReversed();
}
selection.insertPath( path );
}
}
}
mSelection = selection;
}
synchronized( mUserStations ) {
for ( DrawingStationPath p : mUserStations ) {
p.flipXAxis(z);
}
}
}
/* Shift the drawing
* translate the drawing by (x,y)
*/
void shiftDrawing( float x, float y )
{
// if ( mStations != null ) {
// synchronized( mStations ) {
// for ( DrawingStationName st : mStations ) {
// st.shiftBy( x, y );
// }
// }
// }
if ( mCurrentStack != null ){
synchronized( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand cmd = (ICanvasCommand) i.next();
cmd.shiftPathBy( x, y );
}
}
}
if ( mSelection != null ) {
synchronized( mSelection ) {
mSelection.shiftSelectionBy( x, y );
}
}
}
public DrawingCommandManager()
{
mBBox = new RectF();
mNorthLine = null;
mFirstReference = null;
mSecondReference = null;
mGridStack1 = Collections.synchronizedList(new ArrayList<DrawingPath>());
mGridStack10 = Collections.synchronizedList(new ArrayList<DrawingPath>());
mGridStack100 = Collections.synchronizedList(new ArrayList<DrawingPath>());
mLegsStack = Collections.synchronizedList(new ArrayList<DrawingPath>());
mSplaysStack = Collections.synchronizedList(new ArrayList<DrawingPath>());
mCurrentStack = Collections.synchronizedList(new ArrayList<ICanvasCommand>());
mUserStations = Collections.synchronizedList( new ArrayList<DrawingStationPath>());
mRedoStack = Collections.synchronizedList(new ArrayList<ICanvasCommand>());
// mHighlight = Collections.synchronizedList(new ArrayList<DrawingPath>());
mStations = Collections.synchronizedList(new ArrayList<DrawingStationName>());
mMatrix = new Matrix(); // identity
mSelection = new Selection();
mSelected = new SelectionSet();
mMaxAreaIndex = 0;
}
// void debug()
// {
// Log.v("DistoX", "Manager grid " + mGridStack1.toArray().length + " "
// + mGridStack10.toArray().length + " "
// + mGridStack100.toArray().length + " legs "
// + mLegsStack.toArray().length + " "
// + mSplaysStack.toArray().length + " items "
// + mCurrentStack.toArray().length );
// }
void clearSelected() { synchronized( mSelected ) { mSelected.clear(); } }
void clearReferences()
{
synchronized( mGridStack1 ) {
mNorthLine = null;
mFirstReference = null;
mSecondReference = null;
mGridStack1.clear();
mGridStack10.clear();
mGridStack100.clear();
}
synchronized( mLegsStack ) { mLegsStack.clear(); }
synchronized( mSplaysStack ) { mSplaysStack.clear(); }
synchronized( mStations ) { mStations.clear(); }
clearSelected();
synchronized( mSelection ) { mSelection.clearReferencePoints(); }
}
private void clearSketchItems()
{
synchronized( mSelection ) { mSelection.clearSelectionPoints(); }
synchronized( mCurrentStack ) { mCurrentStack.clear(); }
synchronized( mUserStations ) { mUserStations.clear(); }
mRedoStack.clear();
mSelected.clear();
mDisplayPoints = false;
}
void clearDrawing()
{
clearReferences();
clearSketchItems();
// mMatrix = new Matrix(); // identity
}
void setFirstReference( DrawingPath path ) { synchronized( mGridStack1 ) { mFirstReference = path; } }
void setSecondReference( DrawingPath path ) { synchronized( mGridStack1 ) { mSecondReference = path; } }
/* the next index for the ID of the area border
*/
int getNextAreaIndex()
{
++mMaxAreaIndex;
return mMaxAreaIndex;
}
/* return the list of shots that intesect the segment (p1--p2)
*/
List< DrawingPath > getIntersectionShot( LinePoint p1, LinePoint p2 )
{
List< DrawingPath > ret = new ArrayList< DrawingPath >();
for ( DrawingPath p : mLegsStack ) {
if ( p.mType == DrawingPath.DRAWING_PATH_FIXED ) {
if ( p.intersect( p1.mX, p1.mY, p2.mX, p2.mY, null ) ) {
ret.add( p );
}
}
}
return ret;
}
/* Get the station at (x,y)
* Return the station inside the square centered at (x,y) of side 2*mCloseness
*/
DrawingStationName getStationAt( float x, float y ) // x,y canvas coords
{
// Log.v("DistoX", "get station at " + x + " " + y );
for ( DrawingStationName st : mStations ) {
// Log.v("DistoX", "station at " + st.cx + " " + st.cy );
if ( Math.abs( x - st.cx ) < TDSetting.mCloseness
&& Math.abs( y - st.cy ) < TDSetting.mCloseness ) return st;
}
return null;
}
void setDisplayPoints( boolean display ) { mDisplayPoints = display; }
boolean isSelectable() { return mSelection != null; }
// public void clearHighlight()
// {
// for ( DrawingPath p : mHighlight ) {
// if ( p.mType == DrawingPath.DRAWING_PATH_FIXED ) {
// p.mPaint = BrushManager.fixedShotPaint;
// } else {
// p.mPaint = BrushManager.fixedSplayPaint;
// }
// }
// mHighlight.clear();
// }
// public DistoXDBlock setHighlight( int plot_type, float x, float y )
// {
// clearHighlight();
// if ( ! PlotInfo.isSketch2d( plot_type ) ) return null;
// boolean legs = (mDisplayMode & DisplayMode.DISPLAY_LEG) != 0;
// boolean splays = (mDisplayMode & DisplayMode.DISPLAY_SPLAY) != 0;
// if ( mHighlight.size() == 1 ) {
// return mHighlight.get(0).mBlock;
// }
// return null;
// }
/* Set the transform matrix for the canvas rendering of the drawing
* The matrix is diag(s*dx, s*dy)
*/
public void setTransform( float dx, float dy, float s )
{
mMatrix = new Matrix();
mMatrix.postTranslate( dx, dy );
mMatrix.postScale( s, s );
mScale = 1 / s;
mBBox.left = - dx; // scene coords
mBBox.right = mScale * TopoDroidApp.mDisplayWidth - dx;
mBBox.top = - dy;
mBBox.bottom = mScale * TopoDroidApp.mDisplayHeight - dy;
synchronized ( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand c = (ICanvasCommand) i.next();
if ( c.commandType() == 0 ) {
DrawingPath path = (DrawingPath)c;
if ( path.mType == DrawingPath.DRAWING_PATH_AREA ) {
DrawingAreaPath area = (DrawingAreaPath)path;
area.shiftShaderBy( dx, dy, s );
}
}
}
}
// FIXME
// TUNING this is to see how many buckets are on the canvas and how many points they contain
//
// if ( mSelection != null ) {
// int cnt = 0;
// float pts = 0;
// for ( SelectionBucket bucket : mSelection.mBuckets ) {
// if ( bucket.intersects( mBBox ) ) { ++ cnt; pts += bucket.size(); }
// }
// pts /= cnt;
// Log.v("DistoX", "visible buckets " + cnt + " avg pts/bucket " + pts );
// }
}
// oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
void addEraseCommand( EraseCommand cmd )
{
mCurrentStack.add( cmd );
}
/**
* @return result code:
* 0 no erasing
* 1 point erased
* 2 line complete erase
* 3 line start erase
* 4 line end erase
* 5 line split
* 6 area complete erase
* 7 area point erase
*
* x X scene
* y Y scene
* zoom canvas display zoom
*/
int eraseAt( float x, float y, float zoom, EraseCommand eraseCmd )
{
SelectionSet sel = new SelectionSet();
float radius = TDSetting.mCloseCutoff + TDSetting.mEraseness / zoom;
mSelection.selectAt( sel, x, y, radius, false, false, false );
int ret = 0;
if ( sel.size() > 0 ) {
synchronized( mCurrentStack ) {
for ( SelectionPoint pt : sel.mPoints ) {
DrawingPath path = pt.mItem;
if ( path.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath line = (DrawingLinePath)path;
// ArrayList< LinePoint > points = line.mPoints;
// int size = points.size();
LinePoint first = line.mFirst;
LinePoint last = line.mLast;
int size = line.size();
if ( size <= 2 || ( size == 3 && pt.mPoint == first.mNext ) ) // 2-point line OR erase midpoint of a 3-point line
{
ret = 2;
eraseCmd.addAction( EraseAction.ERASE_REMOVE, path );
mCurrentStack.remove( path );
synchronized( mSelection ) {
mSelection.removePath( path );
}
}
else if ( pt.mPoint == first ) // erase first point of the multi-point line (2016-05-14)
{
ret = 3;
eraseCmd.addAction( EraseAction.ERASE_MODIFY, path );
// LinePoint lp = points.get(0);
LinePoint lp = first;
doRemoveLinePoint( line, pt.mPoint, pt );
synchronized( mSelection ) {
mSelection.removeLinePoint( line, lp ); // index = 0
// mSelection.mPoints.remove( pt ); // index = 1
}
line.retracePath();
}
else if ( pt.mPoint == first.mNext ) // erase second point of the multi-point line
{
ret = 3;
eraseCmd.addAction( EraseAction.ERASE_MODIFY, path );
// LinePoint lp = points.get(0);
LinePoint lp = first;
doRemoveLinePoint( line, lp, null );
doRemoveLinePoint( line, pt.mPoint, pt );
synchronized( mSelection ) {
mSelection.removeLinePoint( line, lp ); // index = 0
mSelection.mPoints.remove( pt ); // index = 1
}
line.retracePath();
}
else if ( pt.mPoint == last.mPrev ) // erase second-to-last of multi-point line
{
ret = 4;
eraseCmd.addAction( EraseAction.ERASE_MODIFY, path );
// LinePoint lp = points.get(size-1);
LinePoint lp = last;
doRemoveLinePoint( line, lp, null );
doRemoveLinePoint( line, pt.mPoint, pt );
synchronized( mSelection ) {
mSelection.removeLinePoint( line, lp ); // size -1
mSelection.mPoints.remove( pt ); // size -2
}
line.retracePath();
} else { // erase a point in the middle of multi-point line
ret = 5;
doSplitLine( line, pt.mPoint, eraseCmd );
break; // IMPORTANT break the for-loop
}
} else if ( path.mType == DrawingPath.DRAWING_PATH_AREA ) {
DrawingAreaPath area = (DrawingAreaPath)path;
if ( area.size() <= 3 ) {
ret = 6;
eraseCmd.addAction( EraseAction.ERASE_REMOVE, path );
mCurrentStack.remove( path );
synchronized( mSelection ) {
mSelection.removePath( path );
}
} else {
ret = 7;
eraseCmd.addAction( EraseAction.ERASE_MODIFY, path );
doRemoveLinePoint( area, pt.mPoint, pt );
area.retracePath();
}
} else if ( path.mType == DrawingPath.DRAWING_PATH_POINT ) {
ret = 1;
eraseCmd.addAction( EraseAction.ERASE_REMOVE, path );
mCurrentStack.remove( path );
synchronized( mSelection ) {
mSelection.removePath( path );
}
}
}
}
}
// checkLines();
return ret;
}
/* Split the line at the point lp
* The erase command is updated with the removal of the original line and the insert
* of the two new pieces
// called from synchronized( CurrentStack ) context
// called only by eraseAt
*/
private void doSplitLine( DrawingLinePath line, LinePoint lp, EraseCommand eraseCmd )
{
DrawingLinePath line1 = new DrawingLinePath( line.mLineType );
DrawingLinePath line2 = new DrawingLinePath( line.mLineType );
if ( line.splitAt( lp, line1, line2, true ) ) {
// Log.v("DistoX", "split " + line.size() + " ==> " + line1.size() + " " + line2.size() );
// synchronized( mCurrentStack ) // not neceessary: called in synchronized context
{
eraseCmd.addAction( EraseAction.ERASE_REMOVE, line );
mCurrentStack.remove( line );
if ( line1.size() > 1 ) {
eraseCmd.addAction( EraseAction.ERASE_INSERT, line1 );
mCurrentStack.add( line1 );
}
if ( line2.size() > 1 ) {
eraseCmd.addAction( EraseAction.ERASE_INSERT, line2 );
mCurrentStack.add( line2 );
}
}
synchronized( mSelection ) {
mSelection.removePath( line );
if ( line1.size() > 1 ) mSelection.insertLinePath( line1 );
if ( line2.size() > 1 ) mSelection.insertLinePath( line2 );
}
} else {
// FIXME
// TDLog.Error( "FAILED splitAt " + lp.mX + " " + lp.mY );
// line.dump();
}
// checkLines();
}
void splitLine( DrawingLinePath line, LinePoint lp )
{
if ( lp == null ) {
return;
}
// if ( lp == line.mPoints.get(0) )
if ( lp == line.mFirst )
{
return; // cannot split at first point
}
// int size = line.mPoints.size();
int size = line.size();
if ( size == 2 ) {
return;
}
// if ( lp == line.mPoints.get(size-1) )
if ( lp == line.mLast )
{
return; // cannot split at last point
}
clearSelected();
DrawingLinePath line1 = new DrawingLinePath( line.mLineType );
DrawingLinePath line2 = new DrawingLinePath( line.mLineType );
if ( line.splitAt( lp, line1, line2, false ) ) {
synchronized( mCurrentStack ) {
mCurrentStack.remove( line );
mCurrentStack.add( line1 );
mCurrentStack.add( line2 );
}
synchronized( mSelection ) {
mSelection.removePath( line );
mSelection.insertLinePath( line1 );
mSelection.insertLinePath( line2 );
}
}
// checkLines();
}
// called from synchronized( mCurrentStack )
private void doRemoveLinePoint( DrawingPointLinePath line, LinePoint point, SelectionPoint sp )
{
// int size = line.mPoints.size();
// for ( int k=0; k<size; ++k ) {
// LinePoint lp = line.mPoints.get( k );
// if ( lp == point ) {
// line.mPoints.remove( k );
// mSelection.mPoints.remove( sp );
// return;
// }
// }
//line.mPoints.remove( point );
line.remove( point );
if ( sp != null ) { // sp can be null
synchronized( mSelection ) {
mSelection.removePoint( sp );
}
}
// checkLines();
}
boolean removeLinePoint( DrawingPointLinePath line, LinePoint point, SelectionPoint sp )
{
if ( point == null ) return false;
// int size = line.mPoints.size();
int size = line.size();
if ( size <= 2 ) return false;
synchronized( mSelection ) { clearSelected(); }
// for ( int k=0; k<size; ++k )
for ( LinePoint lp = line.mFirst; lp != null; lp = lp.mNext )
{
// LinePoint lp = line.mPoints.get( k );
if ( lp == point ) {
synchronized( mCurrentStack ) {
// line.mPoints.remove( k );
line.remove( point );
synchronized( mSelection ) {
mSelection.removePoint( sp );
}
// checkLines();
return true;
}
}
}
// checkLines();
return false;
}
private void doDeletePath( DrawingPath path )
{
synchronized( mCurrentStack ) {
mCurrentStack.remove( path );
}
synchronized( mSelection ) {
mSelection.removePath( path );
clearSelected();
}
}
void deletePath( DrawingPath path, EraseCommand eraseCmd ) // called by DrawingSurface
{
doDeletePath( path );
// checkLines();
if ( eraseCmd != null ) eraseCmd.addAction( EraseAction.ERASE_REMOVE, path );
}
void deleteSectionLine( DrawingPath line, String scrap, EraseCommand cmd )
{
synchronized( mCurrentStack ) {
int index = BrushManager.mPointLib.mPointSectionIndex;
if ( index >= 0 ) {
ArrayList<DrawingPath> todo = new ArrayList<DrawingPath>();
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand c = (ICanvasCommand) i.next();
if ( c.commandType() == 0 ) {
DrawingPath p = (DrawingPath)c;
if ( p.mType == DrawingPath.DRAWING_PATH_POINT ) {
DrawingPointPath pt = (DrawingPointPath)p;
if ( pt.mPointType == index && scrap.equals( pt.getOption( "-scrap" ) ) ) {
todo.add(p);
}
}
}
}
for ( DrawingPath pp : todo ) deletePath( pp, cmd );
}
deletePath( line, cmd );
}
}
void sharpenLine( DrawingLinePath line )
{
synchronized( mCurrentStack ) {
line.makeSharp( );
}
// checkLines();
}
void reduceLine( DrawingLinePath line )
{
synchronized( mSelection ) {
mSelection.removePath( line );
clearSelected();
}
synchronized( mCurrentStack ) {
line.makeReduce( );
}
synchronized( mSelection ) {
mSelection.insertPath( line );
}
// checkLines();
}
void closeLine( DrawingLinePath line )
{
synchronized( mCurrentStack ) {
SelectionPoint sp = mSelection.getSelectionPoint( line.mLast );
line.makeClose( );
// rebucket last line point
mSelection.rebucket( sp );
}
}
// ooooooooooooooooooooooooooooooooooooooooooooooooooooo
public void setDisplayMode( int mode ) { mDisplayMode = mode; }
public int getDisplayMode( ) { return mDisplayMode; }
// void setBounds( float x1, float x2, float y1, float y2 )
// {
// mSelection = new Selection();
// }
// try {
// mSelection = new Selection( x1, x2, y1, y2, 5.0f );
// mSelected = new SelectionSet();
// } catch ( SelectionException e ) {
// TDLog.Error( "oversize: unable to select " );
// mSelection = null;
// }
// }
// FIXME LEGS_SPLAYS
void resetFixedPaint( Paint paint )
{
if( mLegsStack != null ) {
synchronized( mLegsStack ) {
final Iterator i = mLegsStack.iterator();
while ( i.hasNext() ){
final DrawingPath path = (DrawingPath) i.next();
if ( path.mBlock == null || ( ! path.mBlock.mMultiBad ) ) {
path.setPaint( paint );
}
}
}
}
if( mSplaysStack != null ) {
synchronized( mSplaysStack ) {
final Iterator i = mSplaysStack.iterator();
while ( i.hasNext() ){
final DrawingPath path = (DrawingPath) i.next();
if ( path.mBlock == null || ( ! path.mBlock.mMultiBad ) ) {
path.setPaint( paint );
}
}
}
}
}
public void addLegPath( DrawingPath path, boolean selectable )
{
if ( mLegsStack == null ) return;
synchronized( mLegsStack ) {
mLegsStack.add( path );
if ( selectable ) {
synchronized( mSelection ) {
if ( path.mBlock != null ) {
// Log.v( "DistoX", "selection add fixed path " + path.mBlock.mFrom + " " + path.mBlock.mTo );
}
mSelection.insertPath( path );
}
}
}
}
public void addSplayPath( DrawingPath path, boolean selectable )
{
if ( mSplaysStack == null ) return;
synchronized( mSplaysStack ) {
mSplaysStack.add( path );
if ( selectable ) {
synchronized( mSelection ) {
if ( path.mBlock != null ) {
// Log.v( "DistoX", "selection add fixed path " + path.mBlock.mFrom + " " + path.mBlock.mTo );
}
mSelection.insertPath( path );
}
}
}
}
public void setNorth( DrawingPath path )
{
mNorthLine = path;
}
public void addGrid( DrawingPath path, int k )
{
if ( mGridStack1 == null ) return;
synchronized( mGridStack1 ) {
switch (k) {
case 1: mGridStack1.add( path ); break;
case 10: mGridStack10.add( path ); break;
case 100: mGridStack100.add( path ); break;
}
}
}
// void setScaleBar( float x0, float y0 )
// {
// if ( mCurrentStack.size() > 0 ) return;
// DrawingLinePath scale_bar = new DrawingLinePath( BrushManager.mLineLib.mLineSectionIndex );
// scale_bar.addStartPoint( x0 - 50, y0 );
// scale_bar.addPoint( x0 + 50, y0 ); // 5 meters
// synchronized( mCurrentStack ) {
// mCurrentStack.add( scale_bar );
// }
// }
DrawingStationPath getUserStation( String name )
{
for ( DrawingStationPath p : mUserStations ) if ( p.mName.equals( name ) ) return p;
return null;
}
void removeUserStation( DrawingStationPath path )
{
synchronized( mUserStations ) {
mUserStations.remove( path );
}
}
// boolean hasUserStation( String name )
// {
// for ( DrawingStationPath p : mUserStations ) if ( p.mName.equals( name ) ) return true;
// return false;
// }
void addUserStation( DrawingStationPath path )
{
synchronized( mUserStations ) {
mUserStations.add( (DrawingStationPath)path );
}
}
void addCommand( DrawingPath path )
{
// TDLog.Log( TDLog.LOG_PLOT, "addCommand stack size " + mCurrentStack.size() );
// TDLog.Log( TDLog.LOG_PLOT, "addCommand path " + path.toString() );
// Log.v("DistoX", "add command type " + path.mType + " " + path.left + " " + path.top + " "
// + mBBox.left + " " + mBBox.top + " " + mBBox.right + " " + mBBox.bottom );
mRedoStack.clear();
if ( path.mType == DrawingPath.DRAWING_PATH_AREA ) {
DrawingAreaPath area = (DrawingAreaPath)path;
if ( area.mAreaCnt > mMaxAreaIndex ) {
mMaxAreaIndex = area.mAreaCnt;
}
}
// if ( path.mType == DrawingPath.DRAWING_PATH_LINE ) {
// DrawingLinePath line = (DrawingLinePath)path;
// LinePoint lp = line.mFirst;
// Log.v("PTDistoX", "add path. size " + line.size() + " start " + lp.mX + " " + lp.mY );
// }
synchronized( mCurrentStack ) {
mCurrentStack.add( path );
}
synchronized( mSelection ) {
mSelection.insertPath( path );
}
// checkLines();
}
public void deleteSectionPoint( String scrap_name, EraseCommand cmd )
{
int index = BrushManager.mPointLib.mPointSectionIndex;
synchronized( mCurrentStack ) {
for ( ICanvasCommand icc : mCurrentStack ) { // FIXME reverse_iterator
if ( icc.commandType() == 0 ) { // DrawingPath
DrawingPath path = (DrawingPath)icc;
if ( path.mType == DrawingPath.DRAWING_PATH_POINT ) {
DrawingPointPath dpp = (DrawingPointPath) path;
if ( dpp.mPointType == index ) {
String vals[] = dpp.mOptions.split(" ");
int len = vals.length;
for ( int k = 0; k < len; ++k ) {
if ( scrap_name.equals( vals[k] ) ) {
deletePath( path, cmd );
return;
}
}
}
}
}
}
}
}
// called by DrawingSurface.getBitmap()
public RectF getBitmapBounds()
{
RectF bounds = new RectF();
RectF b = new RectF();
if( mSplaysStack != null ) {
synchronized( mSplaysStack ) {
final Iterator i = mSplaysStack.iterator();
while ( i.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i.next();
drawingPath.mPath.computeBounds( b, true );
bounds.union( b );
}
}
}
if( mLegsStack != null ) {
synchronized( mLegsStack ) {
final Iterator i = mLegsStack.iterator();
while ( i.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i.next();
drawingPath.mPath.computeBounds( b, true );
bounds.union( b );
}
}
}
if( mCurrentStack != null ){
synchronized( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand cmd = (ICanvasCommand) i.next();
cmd.computeBounds( b, true );
bounds.union( b );
}
}
}
return bounds;
}
private float mBitmapScale = 1;
// returns the last used bitmap scale
float getBitmapScale() { return mBitmapScale; }
public Bitmap getBitmap()
{
RectF bounds = getBitmapBounds();
// TDLog.Log( TDLog.LOG_PLOT, "getBitmap Bounds " + bounds.left + " " + bounds.top + " " + bounds.right + " " + bounds.bottom );
mBitmapScale = TDSetting.mBitmapScale;
int width = (int)((bounds.right - bounds.left + 2 * BORDER) );
int height = (int)((bounds.bottom - bounds.top + 2 * BORDER) );
int max = (int)( 8 * 1024 * 1024 / (mBitmapScale * mBitmapScale) ); // 16 MB 2 B/pixel
while ( width*height > max ) {
mBitmapScale /= 2;
max *= 4;
}
width = (int)((bounds.right - bounds.left + 2 * BORDER) * mBitmapScale );
height = (int)((bounds.bottom - bounds.top + 2 * BORDER) * mBitmapScale );
Bitmap bitmap = null;
while ( bitmap == null && mBitmapScale > 0.05 ) {
try {
// bitmap = Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888);
bitmap = Bitmap.createBitmap (width, height, Bitmap.Config.RGB_565);
} catch ( OutOfMemoryError e ) {
mBitmapScale /= 2;
width = (int)((bounds.right - bounds.left + 2 * BORDER) * mBitmapScale );
height = (int)((bounds.bottom - bounds.top + 2 * BORDER) * mBitmapScale );
} catch ( IllegalArgumentException e ) {
TDLog.Error("create bitmap illegal arg " + e.getMessage() );
return null;
}
}
if ( mBitmapScale <= 0.05 ) return null;
if ( bitmap == null ) return null;
// Log.v( "DistoX", "PNG mBitmapScale " + mBitmapScale + "/" + TDSetting.mBitmapScale + " " + width + "x" + height );
Canvas c = new Canvas (bitmap);
// c.drawColor(TDSetting.mBitmapBgcolor, PorterDuff.Mode.CLEAR);
c.drawColor( TDSetting.mBitmapBgcolor );
// commandManager.execute All(c,previewDoneHandler);
// previewPath.draw(c);
c.drawBitmap (bitmap, 0, 0, null);
Matrix mat = new Matrix();
float sca = 1 / mBitmapScale;
mat.postTranslate( BORDER - bounds.left, BORDER - bounds.top );
mat.postScale( mBitmapScale, mBitmapScale );
if ( mGridStack1 != null ) {
synchronized( mGridStack1 ) {
final Iterator i1 = mGridStack1.iterator();
while ( i1.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i1.next();
drawingPath.draw( c, mat, sca, null );
}
final Iterator i10 = mGridStack10.iterator();
while ( i10.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i10.next();
drawingPath.draw( c, mat, sca, null );
}
final Iterator i100 = mGridStack100.iterator();
while ( i100.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i100.next();
drawingPath.draw( c, mat, sca, null );
}
if ( mNorthLine != null ) mNorthLine.draw( c, mat, sca, null );
}
}
if ( mSplaysStack != null ) {
synchronized( mSplaysStack ) {
final Iterator i = mSplaysStack.iterator();
while ( i.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i.next();
drawingPath.draw( c, mat, sca, null );
}
}
}
if ( mLegsStack != null ) {
synchronized( mLegsStack ) {
final Iterator i = mLegsStack.iterator();
while ( i.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i.next();
drawingPath.draw( c, mat, sca, null );
}
}
}
if ( mStations != null ) {
synchronized( mStations ) {
for ( DrawingStationName st : mStations ) {
st.draw( c, mat, sca, null );
}
}
}
if( mCurrentStack != null ){
synchronized( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand cmd = (ICanvasCommand) i.next();
cmd.draw( c, mat, sca, null );
}
}
}
// checkLines();
return bitmap;
}
static final String actionName[] = { "remove", "insert", "modify" };
public void undo ()
{
final int length = currentStackLength();
if ( length > 0) {
final ICanvasCommand cmd = mCurrentStack.get( length - 1 );
synchronized( mCurrentStack ) {
mCurrentStack.remove( length - 1 );
// cmd.undoCommand();
}
mRedoStack.add( cmd );
if ( cmd.commandType() == 0 ) {
synchronized( mSelection ) {
mSelection.removePath( (DrawingPath)cmd );
}
} else { // EraseCommand
EraseCommand eraseCmd = (EraseCommand)cmd;
int na = eraseCmd.mActions.size();
while ( na > 0 ) {
--na;
EraseAction action = eraseCmd.mActions.get( na );
DrawingPath path = action.mPath;
// Log.v("DistoX", "UNDO " + actionName[action.mType] + " path " + path.toString() );
if ( action.mInitialType == EraseAction.ERASE_INSERT ) {
synchronized( mCurrentStack ) {
mCurrentStack.remove( path );
}
synchronized( mSelection ) {
mSelection.removePath( path );
}
} else if ( action.mType == EraseAction.ERASE_REMOVE ) {
synchronized( mCurrentStack ) {
action.restorePoints( true ); // true: use old points
mCurrentStack.add( path );
}
synchronized( mSelection ) {
mSelection.insertPath( path );
}
} else if ( action.mType == EraseAction.ERASE_MODIFY ) { // undo modify
synchronized( mSelection ) {
mSelection.removePath( path );
}
synchronized( mCurrentStack ) {
action.restorePoints( true );
}
synchronized( mSelection ) {
mSelection.insertPath( path );
}
}
}
}
}
// checkLines();
}
public int currentStackLength()
{
final int length = mCurrentStack.toArray().length;
return length;
}
// line points are scene-coords
// continuation is checked in canvas-coords: canvas = offset + scene * zoom
DrawingLinePath getLineToContinue( LinePoint lp, int type, float zoom )
{
String group = BrushManager.getLineGroup( type );
if ( group == null ) return null;
float delta = 2 * TDSetting.mCloseness / zoom;
DrawingLinePath ret = null;
synchronized( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
ICanvasCommand cmd = (ICanvasCommand) i.next();
if ( cmd.commandType() != 0 ) continue; // FIXME EraseCommand
final DrawingPath drawingPath = (DrawingPath)cmd;
if ( drawingPath.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath linePath = (DrawingLinePath)drawingPath;
// if ( linePath.mLineType == type )
if ( group.equals( BrushManager.getLineGroup( linePath.mLineType ) ) )
{
if ( linePath.mFirst.distance( lp ) < delta || linePath.mLast.distance( lp ) < delta ) {
if ( ret != null ) return null; // ambiguity
ret = linePath;
}
}
}
}
}
// if ( ret != null ) mSelection.removePath( ret ); // FIXME do not remove continuation line
// checkLines();
return ret;
}
/** add the points of the first line to the second line
*/
void addLineToLine( DrawingLinePath line, DrawingLinePath line0 )
{
synchronized( mSelection ) {
mSelection.removePath( line0 );
}
synchronized( mCurrentStack ) {
boolean reverse = line0.mFirst.distance( line.mFirst ) < line0.mLast.distance( line.mFirst );
if ( reverse ) line0.reversePath();
line0.append( line );
if ( reverse ) {
line0.reversePath();
line0.computeUnitNormal();
}
}
synchronized( mSelection ) {
mSelection.insertPath( line0 );
}
// checkLines();
}
private boolean showStationSplays( DrawingPath p, ArrayList<String> splay_stations )
{
DistoXDBlock blk = p.mBlock;
if ( blk == null ) return false;
String station = blk.mFrom;
if ( station == null || station.length() == 0 ) return false;
return splay_stations.contains( station );
}
// N.B. doneHandler is not used
public void executeAll( Canvas canvas, float zoom, ArrayList<String> splay_stations )
{
if ( canvas == null ) {
TDLog.Error( "drawing executeAll: null canvas");
return;
}
boolean legs = (mDisplayMode & DisplayMode.DISPLAY_LEG ) != 0;
boolean splays = (mDisplayMode & DisplayMode.DISPLAY_SPLAY ) != 0;
boolean stations = (mDisplayMode & DisplayMode.DISPLAY_STATION ) != 0;
boolean grids = (mDisplayMode & DisplayMode.DISPLAY_GRID ) != 0;
boolean outline = (mDisplayMode & DisplayMode.DISPLAY_OUTLINE ) != 0;
if( grids && mGridStack1 != null ) {
synchronized( mGridStack1 ) {
if ( mScale < 1 ) {
final Iterator i1 = mGridStack1.iterator();
while ( i1.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i1.next();
drawingPath.draw( canvas, mMatrix, mScale, mBBox );
}
}
if ( mScale < 10 ) {
final Iterator i10 = mGridStack10.iterator();
while ( i10.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i10.next();
drawingPath.draw( canvas, mMatrix, mScale, mBBox );
}
}
final Iterator i100 = mGridStack100.iterator();
while ( i100.hasNext() ){
final DrawingPath drawingPath = (DrawingPath) i100.next();
drawingPath.draw( canvas, mMatrix, mScale, mBBox );
}
if ( mNorthLine != null ) mNorthLine.draw( canvas, mMatrix, mScale, mBBox );
}
}
if ( legs && mLegsStack != null ) {
synchronized( mLegsStack ) {
final Iterator i = mLegsStack.iterator();
while ( i.hasNext() ){
final DrawingPath path = (DrawingPath) i.next();
path.draw( canvas, mMatrix, mScale, mBBox );
}
}
}
if ( mSplaysStack != null && ( splays || splay_stations.size() > 0 ) ) {
synchronized( mSplaysStack ) {
final Iterator i = mSplaysStack.iterator();
while ( i.hasNext() ){
final DrawingPath path = (DrawingPath) i.next();
if ( splays || showStationSplays( path, splay_stations ) ) {
path.draw( canvas, mMatrix, mScale, mBBox );
}
}
}
}
if ( stations && mStations != null ) {
synchronized( mStations ) {
for ( DrawingStationName st : mStations ) {
st.draw( canvas, mMatrix, mScale, mBBox );
}
}
}
if ( mCurrentStack != null ){
synchronized( mCurrentStack ) {
if ( outline ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand cmd = (ICanvasCommand) i.next();
if ( cmd.commandType() == 0 ) {
DrawingPath path = (DrawingPath)cmd;
if ( path.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath line = (DrawingLinePath)path;
if ( line.hasOutline() ) {
cmd.draw( canvas, mMatrix, mScale, mBBox );
}
}
}
}
} else {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ){
final ICanvasCommand cmd = (ICanvasCommand) i.next();
if ( cmd.commandType() == 0 ) {
cmd.draw( canvas, mMatrix, mScale, mBBox );
DrawingPath path = (DrawingPath)cmd;
if ( path.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath line = (DrawingLinePath)path;
if ( line.mLineType == BrushManager.mLineLib.mLineSectionIndex ) { // add tick to section-lines
LinePoint lp = line.mFirst;
Path path1 = new Path();
path1.moveTo( lp.mX, lp.mY );
path1.lineTo( lp.mX+line.mDx*10, lp.mY+line.mDy*10 );
path1.transform( mMatrix );
canvas.drawPath( path1, BrushManager.mStationSymbol.mPaint );
}
}
}
}
}
}
}
if ( ! TDSetting.mAutoStations ) {
synchronized( mUserStations ) {
for ( DrawingStationPath p : mUserStations ) {
p.draw( canvas, mMatrix, mScale, mBBox );
}
}
}
if ( mDisplayPoints ) {
synchronized( mSelection ) {
float radius = TDSetting.mDotRadius/zoom;
final Iterator i = mSelection.mBuckets.iterator();
while ( i.hasNext() ) {
final SelectionBucket bucket = (SelectionBucket) i.next();
if ( bucket.intersects( mBBox ) ) {
for ( SelectionPoint pt : bucket.mPoints ) {
int type = pt.type();
if ( ( type == DrawingPath.DRAWING_PATH_FIXED && ! legs )
|| ( type == DrawingPath.DRAWING_PATH_SPLAY && ! splays )
|| ( type == DrawingPath.DRAWING_PATH_NAME && ! stations ) ) continue;
float x, y;
if ( pt.mPoint != null ) { // line-point
x = pt.mPoint.mX;
y = pt.mPoint.mY;
} else {
x = pt.mItem.cx;
y = pt.mItem.cy;
}
Path path = new Path();
path.addCircle( x, y, radius, Path.Direction.CCW );
path.transform( mMatrix );
canvas.drawPath( path, BrushManager.highlightPaint2 );
}
}
}
// for ( SelectionPoint pt : mSelection.mPoints ) { // FIXME SELECTION
// float x, y;
// if ( pt.mPoint != null ) { // line-point
// x = pt.mPoint.mX;
// y = pt.mPoint.mY;
// } else {
// x = pt.mItem.cx;
// y = pt.mItem.cy;
// }
// Path path = new Path();
// path.addCircle( x, y, radius, Path.Direction.CCW );
// path.transform( mMatrix );
// canvas.drawPath( path, BrushManager.highlightPaint2 );
// }
}
synchronized( mSelected ) {
if ( mSelected.mPoints.size() > 0 ) { // FIXME SELECTIOM
float radius = 4*TDSetting.mDotRadius/zoom;
Path path;
SelectionPoint sp = mSelected.mHotItem;
if ( sp != null ) {
float x, y;
LinePoint lp = sp.mPoint;
DrawingPath item = sp.mItem;
LinePoint lp1 = sp.mLP1;
LinePoint lp2 = sp.mLP2;
if ( lp != null ) { // line-point
x = lp.mX;
y = lp.mY;
} else {
x = item.cx;
y = item.cy;
}
path = new Path();
path.addCircle( x, y, radius, Path.Direction.CCW );
path.transform( mMatrix );
canvas.drawPath( path, BrushManager.highlightPaint2 );
if ( lp != null && lp.has_cp ) {
path = new Path();
path.moveTo( lp.mX1, lp.mY1 );
path.lineTo( lp.mX2, lp.mY2 );
path.lineTo( x, y );
path.addCircle( lp.mX1, lp.mY1, radius/2, Path.Direction.CCW );
path.addCircle( lp.mX2, lp.mY2, radius/2, Path.Direction.CCW );
path.transform( mMatrix );
canvas.drawPath( path, BrushManager.highlightPaint3 );
}
if ( item.mType == DrawingPath.DRAWING_PATH_LINE ) {
Paint paint = BrushManager.fixedYellowPaint;
DrawingLinePath line = (DrawingLinePath) item;
lp = line.mFirst;
LinePoint lpn = lp1;
if ( lp == lp1 ) {
paint = BrushManager.fixedOrangePaint;
lpn = lp2;
}
path = new Path();
path.moveTo( lp.mX+line.mDx*10, lp.mY+line.mDy*10 );
path.lineTo( lp.mX, lp.mY );
for ( lp = lp.mNext; lp != lpn && lp != null; lp = lp.mNext ) {
if ( lp.has_cp ) {
path.cubicTo( lp.mX1, lp.mY1, lp.mX2, lp.mY2, lp.mX, lp.mY );
} else {
path.lineTo( lp.mX, lp.mY );
}
}
path.transform( mMatrix );
canvas.drawPath( path, paint );
if ( lp != lp2 ) {
path = new Path();
path.moveTo( lp.mX, lp.mY );
for ( lp = lp.mNext; lp != lp2 && lp != null; lp = lp.mNext ) {
if ( lp.has_cp ) {
path.cubicTo( lp.mX1, lp.mY1, lp.mX2, lp.mY2, lp.mX, lp.mY );
} else {
path.lineTo( lp.mX, lp.mY );
}
}
path.transform( mMatrix );
canvas.drawPath( path, BrushManager.fixedOrangePaint );
}
if ( lp != null && lp.mNext != null ) {
path = new Path();
path.moveTo( lp.mX, lp.mY );
for ( lp = lp.mNext; lp != null; lp = lp.mNext ) {
if ( lp.has_cp ) {
path.cubicTo( lp.mX1, lp.mY1, lp.mX2, lp.mY2, lp.mX, lp.mY );
} else {
path.lineTo( lp.mX, lp.mY );
}
}
path.transform( mMatrix );
canvas.drawPath( path, BrushManager.fixedYellowPaint );
}
}
}
radius = radius/3; // 2/zoom;
for ( SelectionPoint pt : mSelected.mPoints ) {
float x, y;
if ( pt.mPoint != null ) { // line-point
x = pt.mPoint.mX;
y = pt.mPoint.mY;
} else {
x = pt.mItem.cx;
y = pt.mItem.cy;
}
path = new Path();
path.addCircle( x, y, radius, Path.Direction.CCW );
path.transform( mMatrix );
canvas.drawPath( path, BrushManager.highlightPaint );
}
}
}
}
synchronized( mGridStack1 ) {
if ( mFirstReference != null ) mFirstReference.draw( canvas, mMatrix, mScale, null );
if ( mSecondReference != null ) mSecondReference.draw( canvas, mMatrix, mScale, null );
}
}
// boolean hasStationName( String name )
// {
// if ( name == null ) return false;
// synchronized( mCurrentStack ) {
// final Iterator i = mCurrentStack.iterator();
// while ( i.hasNext() ){
// final ICanvasCommand cmd = (ICanvasCommand) i.next();
// if ( cmd.commandType() == 0 ) {
// DrawingPath p = (DrawingPath) cmd;
// if ( p.mType == DrawingPath.DRAWING_PATH_STATION ) {
// DrawingStationPath sp = (DrawingStationPath)p;
// if ( name.equals( sp.mName ) ) return true;
// }
// }
// }
// }
// return false;
// }
public boolean hasMoreRedo()
{
return mRedoStack.toArray().length > 0;
}
public boolean hasMoreUndo()
{
return mCurrentStack.toArray().length > 0;
}
public void redo()
{
final int length = mRedoStack.toArray().length;
if ( length > 0) {
final ICanvasCommand cmd = mRedoStack.get( length - 1 );
mRedoStack.remove( length - 1 );
if ( cmd.commandType() == 0 ) {
DrawingPath redoCommand = (DrawingPath)cmd;
synchronized( mCurrentStack ) {
mCurrentStack.add( redoCommand );
}
synchronized( mSelection ) {
mSelection.insertPath( redoCommand );
}
} else {
EraseCommand eraseCmd = (EraseCommand) cmd;
for ( EraseAction action : eraseCmd.mActions ) {
DrawingPath path = action.mPath;
// Log.v("DistoX", "REDO " + actionName[action.mType] + " path " + path.mType );
if ( action.mInitialType == EraseAction.ERASE_INSERT ) {
synchronized( mCurrentStack ) {
mCurrentStack.add( path );
}
synchronized( mSelection ) {
mSelection.insertPath( path );
}
} else if ( action.mType == EraseAction.ERASE_REMOVE ) {
synchronized( mCurrentStack ) {
mCurrentStack.remove( path );
}
synchronized( mSelection ) {
mSelection.removePath( path );
}
} else if ( action.mType == EraseAction.ERASE_MODIFY ) {
synchronized( mSelection ) {
mSelection.removePath( path );
}
synchronized( mCurrentStack ) {
action.restorePoints( false ); // false: use new points
}
synchronized( mSelection ) {
mSelection.insertPath( path );
}
}
}
synchronized( mCurrentStack ) {
mCurrentStack.add( cmd );
}
}
}
// checkLines();
}
boolean setRangeAt( float x, float y, float zoom, int type )
{
SelectionPoint sp1 = mSelected.mHotItem;
if ( sp1 == null ) {
// Log.v("DistoX", "set range at: hotItem is null" );
return false;
}
DrawingPath item = sp1.mItem;
if ( item.mType != DrawingPath.DRAWING_PATH_LINE && item.mType != DrawingPath.DRAWING_PATH_AREA ) {
// Log.v("DistoX", "set range at: item not line/area" );
// mSelected.clear();
return false;
}
float radius = TDSetting.mCloseCutoff + TDSetting.mCloseness / zoom;
SelectionPoint sp2 = null;
synchronized ( mSelected ) {
sp2 = mSelection.selectOnItemAt( item, x, y, 4*radius );
}
if ( sp2 == null ) {
// Log.v("DistoX", "set range at: select on Item return null");
mSelected.clear();
return false;
}
// range is sp1 -- sp2
LinePoint lp1 = sp1.mPoint;
LinePoint lp2 = sp2.mPoint;
int cnt = 0;
LinePoint lp = lp1;
for ( ; lp != null; lp=lp.mNext ) { ++cnt; if ( lp == lp2 ) break; }
if ( lp == null ) {
cnt = 0;
for ( lp=lp1; lp != null; lp=lp.mPrev ) { ++cnt; if ( lp == lp2 ) break; }
if ( lp == null ) { // error
// Log.v("DistoX", "set range at: error lp==null");
return false;
}
lp = lp1; lp1 = lp2; lp2 = lp; // swap lp1 <--> lp2
}
LinePoint lp0 = lp1;
float d1 = 0;
float d2 = 0;
int c1 = 0;
int c2 = 0;
for ( int c = cnt/2; c > 0; --c ) {
++ c1;
lp = lp0.mNext;
d1 += lp0.distance( lp );
lp0 = lp;
}
LinePoint lp4 = lp0;
for ( LinePoint lp3 = lp0.mNext; lp3 != lp2 && lp3 != null; lp3=lp3.mNext) {
++ c2;
d2 += lp4.distance( lp3 );
lp4 = lp3;
}
// Log.v("DistoX", "set range d1 " + d1 + " d2 " + d2 + " C " + cnt + " " + c1 + " " + c2 );
// now make the range sp1 -- sp2 and the hotItem the midpoint
SelectionPoint sp = mSelection.getSelectionPoint( lp0 );
sp.mLP1 = lp1;
sp.mLP2 = lp2;
sp.mD1 = d1;
sp.mD2 = d2;
sp.mRangeType = type;
mSelected.clear();
mSelected.addPoint( sp );
mSelected.mHotItem = sp;
return true;
}
public SelectionSet getItemsAt( float x, float y, float zoom )
{
// Log.v( "DistoX", "getItemAt " + x + " " + y + " zoom " + zoom + " selection pts " + mSelection.mPoints.size() );
float radius = TDSetting.mCloseCutoff + TDSetting.mCloseness / zoom;
boolean legs = (mDisplayMode & DisplayMode.DISPLAY_LEG) != 0;
boolean splays = (mDisplayMode & DisplayMode.DISPLAY_SPLAY ) != 0;
boolean stations = (mDisplayMode & DisplayMode.DISPLAY_STATION ) != 0;
synchronized ( mSelected ) {
mSelected.clear();
mSelection.selectAt( mSelected, x, y, radius, legs, splays, stations );
if ( mSelected.mPoints.size() > 0 ) {
mSelected.nextHotItem();
}
}
return mSelected;
}
void splitHotItem()
{
SelectionPoint sp = mSelected.mHotItem;
if ( sp == null ) return;
if ( sp.type() != DrawingPath.DRAWING_PATH_LINE && sp.type() != DrawingPath.DRAWING_PATH_AREA ) return;
LinePoint lp = sp.mPoint;
if ( lp == null ) return;
float x = lp.mX;
float y = lp.mY;
DrawingPointLinePath line = (DrawingPointLinePath)sp.mItem;
LinePoint p1 = line.insertPointAfter( x, y, lp );
SelectionPoint sp1 = null;
synchronized( mSelection ) {
sp1 = mSelection.insertPathPoint( line, p1 );
}
if ( sp1 != null ) {
synchronized( mSelected ) {
mSelected.mPoints.add( sp1 );
}
}
}
private float project( LinePoint q, LinePoint p0, LinePoint p1 )
{
float x01 = p1.mX - p0.mX;
float y01 = p1.mY - p0.mY;
return ((q.mX-p0.mX)*x01 + (q.mY-p0.mY)*y01) / ( x01*x01 + y01*y01 );
}
private float distance( LinePoint q, LinePoint p0, LinePoint p1 )
{
float x01 = p1.mX - p0.mX;
float y01 = p1.mY - p0.mY;
return TDMath.abs( (q.mX-p0.mX)*y01 - (q.mY-p0.mY)*x01 ) / TDMath.sqrt( x01*x01 + y01*y01 );
}
boolean moveHotItemToNearestPoint()
{
SelectionPoint sp = mSelected.mHotItem;
if ( sp == null ) return false;
float x = 0.0f;
float y = 0.0f;
if ( sp.type() == DrawingPath.DRAWING_PATH_POINT ) {
x = sp.mItem.cx;
y = sp.mItem.cy;
} else if ( sp.type() == DrawingPath.DRAWING_PATH_LINE || sp.type() == DrawingPath.DRAWING_PATH_AREA ) {
x = sp.mPoint.mX;
y = sp.mPoint.mY;
} else {
return false;
}
SelectionPoint spmin = mSelection.getNearestPoint( sp, x, y, 10f );
if ( spmin != null ) {
if ( spmin.type() == DrawingPath.DRAWING_PATH_LINE || spmin.type() == DrawingPath.DRAWING_PATH_AREA ) {
x = spmin.mPoint.mX - x;
y = spmin.mPoint.mY - y;
} else {
x = spmin.mItem.cx - x;
y = spmin.mItem.cy - y;
}
// sp.shiftBy( x, y, 0f );
sp.shiftBy( x, y );
}
return true;
}
// return error codes
// -1 no selected point
// -2 selected point not on area border
// -3 no close line
// +1 only a point: nothing to follow
//
int snapHotItemToNearestLine()
{
SelectionPoint sp = mSelected.mHotItem;
// no selected point or selected point not on area border:
if ( sp == null ) return -1;
if ( sp.type() != DrawingPath.DRAWING_PATH_AREA ) return -2;
DrawingPath item = sp.mItem;
DrawingAreaPath area = (DrawingAreaPath)item;
// int k0 = 0;
LinePoint q0 = sp.mPoint;
// ArrayList< LinePoint > pts0 = area.mPoints;
// int size0 = pts0.size();
// for ( ; k0 < size0; ++k0 ) {
// if ( pts0.get(k0) == q0 ) break;
// }
// if ( k0 == size0 ) return false;
// // area border: ... --> q2 --> q0 --> q1 --> ...
// int k1 = (k0+1)%size0;
// int k2 = (k0+size0-1)%size0;
// LinePoint q1 = area.mPoints.get( k1 ); // next point on the area border
// LinePoint q2 = area.mPoints.get( k2 ); // prev point on the area border
LinePoint q1 = area.next( q0 );
LinePoint q2 = area.prev( q0 );
float x = q0.mX;
float y = q0.mY;
float thr = 10f;
float dmin = thr; // require a minimum distance
DrawingPointLinePath lmin = null;
boolean min_is_area = false;
// int kk0 = -1;
// find drawing path with minimal distance from (x,y)
LinePoint pp0 = null;
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath)cmd;
if ( p == item ) continue;
if ( p.mType != DrawingPath.DRAWING_PATH_LINE &&
p.mType != DrawingPath.DRAWING_PATH_AREA ) continue;
DrawingPointLinePath lp = (DrawingPointLinePath)p;
// ArrayList< LinePoint > pts = lp.mPoints;
// int size = pts.size();
// for ( int k=0; k<size; ++k )
int ks = lp.size();
for ( LinePoint pt = lp.mFirst; pt != null && ks > 0; pt = pt.mNext )
{
-- ks;
// float d = pts.get(k).distance( x, y );
float d = pt.distance( x, y );
if ( d < dmin ) {
dmin = d;
// kk0 = k;
pp0 = pt;
lmin = lp;
min_is_area = ( p.mType == DrawingPath.DRAWING_PATH_AREA );
}
}
}
if ( lmin == null ) return -3;
int cmax = area.size() + 1;
// if ( TDLog.LOG_DEBUG ) { // ===== FIRST SET OF LOGS
// TDLog.Debug( "snap to line");
// for ( LinePoint pt = lmin.mFirst; pt!=null; pt=pt.mNext ) TDLog.Debug( pt.mX + " " + pt.mY );
// TDLog.Debug( "snap area");
// for ( LinePoint pt = area.mFirst; pt!=null; pt=pt.mNext ) TDLog.Debug( pt.mX + " " + pt.mY );
// TDLog.Debug( "snap qq0= " + q0.mX + " " + q0.mY + " to pp0= " + pp0.mX + " " + pp0.mY );
// }
int ret = 0; // return code
LinePoint pp1 = lmin.next( pp0 );
LinePoint pp2 = lmin.prev( pp0 );
LinePoint pp10 = null; // current point forward
LinePoint pp20 = null; // current point backward
// LinePoint pp1 = null; // next point forward
// LinePoint pp2 = null; // prev point backwrad
LinePoint qq10 = null;
LinePoint qq20 = null;
LinePoint qq1 = null;
LinePoint qq2 = null;
boolean reverse = false;
int step = 1;
// if ( kk1 >= 0 )
if ( pp1 != null ) {
// TDLog.Debug( "snap pp1 " + pp1.mX + " " + pp1.mY + " FOLLOW LINE FORWARD" );
// pp1 = pts1.get( kk1 );
// pp10 = pts1.get( kk0 );
pp10 = pp0;
// if ( kk2 >= 0 )
if ( pp2 != null ) {
// TDLog.Debug( "snap pp2 " + pp2.mX + " " + pp2.mY );
// pp2 = pts1.get( kk2 );
// pp20 = pts1.get( kk0 );
pp20 = pp0;
}
if ( pp1.distance( q1 ) < pp1.distance( q2 ) ) {
qq1 = q1; // follow border forward
qq10 = q0;
// TDLog.Debug( "snap qq1 " + qq1.mX + " " + qq1.mY + " follow border forward" );
if ( pp2 != null ) {
qq2 = q2;
qq20 = q0;
// TDLog.Debug( "snap qq2 " + qq2.mX + " " + qq2.mY );
}
} else {
reverse = true;
qq1 = q2; // follow border backward
qq10 = q0;
// TDLog.Debug( "snap reverse qq1 " + qq1.mX + " " + qq1.mY + " follow border backward" );
if ( pp2 != null ) {
qq2 = q1;
qq20 = q0;
// TDLog.Debug( "snap qq2 " + qq2.mX + " " + qq2.mY + " follow forward");
}
}
} else if ( pp2 != null ) { // pp10 is null
// pp2 = pts1.get( kk2 );
// pp20 = pts1.get( kk0 );
pp20 = pp0;
// TDLog.Debug( "snap pp1 null pp2 " + pp2.mX + " " + pp2.mY + " FOLLOW LINE BACKWARD" );
if ( pp2.distance( q2 ) < pp2.distance( q1 ) ) {
qq2 = q2;
qq20 = q0;
// TDLog.Debug( "snap qq2 " + qq2.mX + " " + qq2.mY + " follow border backward" );
} else {
reverse = true;
qq2 = q1;
qq20 = q0;
// TDLog.Debug( "snap reverse qq2 " + qq2.mX + " " + qq2.mY + " follow border forward" );
}
} else { // pp10 and pp20 are null: nothing to follow
// copy pp0 to q0
q0.mX = pp0.mX;
q0.mY = pp0.mY;
ret = 1;
}
if ( qq1 != null ) {
// TDLog.Debug( "qq1 not null " + qq1.mX + " " + qq1.mY + " reverse " + reverse );
// follow line pp10 --> pp1 --> ... using step 1
// with border qq10 --> qq1 --> ... using step delta1
for (int c=0; c<cmax; ++c) { // try to move qq1 forward
TDLog.Debug( "snap at qq1 " + qq1.mX + " " + qq1.mY );
float s = project( qq1, pp10, pp1 );
while ( s > 1.0 ) {
pp10 = pp1;
// TDLog.Debug( "snap follow pp10 " + pp10.mX + " " + pp10.mY );
pp1 = lmin.next( pp1 );
if ( pp1 == null ) {
// TDLog.Debug( "snap end of line pp1 null, pp10 " + pp10.mX + " " + pp10.mY );
break;
}
if ( pp1 == pp0 ) {
// TDLog.Debug( "snap pp1 == pp0, pp10 " + pp10.mX + " " + pp10.mY );
break;
}
s = project( qq1, pp10, pp1 );
}
if ( pp1 == null ) break;
float d1 = distance( qq1, pp10, pp1 );
// TDLog.Debug( "distance d1 " + d1 + " s " + s );
if ( s < 0.0f ) break;
if ( d1 > thr || d1 < 0.001f ) break;
qq10 = qq1;
qq1 = (reverse)? area.prev(qq1) : area.next( qq1 );
if ( qq1 == q0 ) break;
}
} else {
// TDLog.Debug( "snap qq1 null" );
qq10 = q0; // FIXME
}
// if ( qq10 != null && pp10 != null ) {
// TDLog.Debug( "QQ10 " + qq10.mX + " " + qq10.mY + " PP10 " + pp10.mX + " " + pp10.mY );
// }
if ( qq2 != null ) {
// TDLog.Debug( "qq2 not null: " + qq2.mX + " " + qq2.mY + " reverse " + reverse );
// follow line pp20 --> pp2 --> ... using step size1-1
// with border qq20 --> qq2 --> ... using step delta2
for (int c=0; c < cmax; ++c) { // try to move qq2 backward
// TDLog.Debug( "snap at qq2 " + qq2.mX + " " + qq2.mY );
float s = project( qq2, pp20, pp2 );
while ( s > 1.0 ) {
pp20 = pp2;
// TDLog.Debug( "snap s>1, follow pp20 " + pp20.mX + " " + pp20.mY );
pp2 = lmin.prev( pp2 );
if ( pp2 == null ) {
// TDLog.Debug( "snap end of line pp2 null, pp20 " + pp20.mX + " " + pp20.mY );
break;
}
if ( pp2 == pp0 ) {
// TDLog.Debug( "snap pp2 == pp0, pp20 " + pp20.mX + " " + pp20.mY );
break;
}
s = project( qq2, pp20, pp2 );
}
if ( pp2 == null ) break;
float d2 = distance( qq2, pp20, pp2 );
// TDLog.Debug( "distance qq2-P_line " + d2 + " s " + s );
if ( s < 0.0f ) break;
if ( d2 > thr || d2 < 0.001f ) break;
qq20 = qq2;
qq2 = (reverse)? area.next(qq2) : area.prev( qq2 );
if ( qq2 == q0 ) break;
}
} else {
// TDLog.Debug( "snap qq2 null");
qq20 = q0; // FIXME
}
// if ( qq20 != null && pp20 != null ) {
// TDLog.Debug( "QQ20 " + qq20.mX + " " + qq20.mY + " PP20 " + pp20.mX + " " + pp20.mY );
// }
if ( qq20 == qq10 || (reverse && pp10 == null) || (!reverse && pp20 == null) ) {
// should not happen, anyways copy pp0 to q0
q0.mX = pp0.mX;
q0.mY = pp0.mY;
ret = 2;
}
synchronized( mCurrentStack ) {
if ( ret == 0 ) {
synchronized( mSelection ) {
mSelection.removePath( area );
}
// next-prev refer to the point list along the area path.
LinePoint next = qq10.mNext; // unlink qq20 -> ... -> qq10
LinePoint prev = qq20.mPrev;
if ( reverse ) { // unlink qq10 -> ... -> qq20
next = qq20.mNext;
prev = qq10.mPrev;
}
if ( prev == null ) {
area.mFirst = null; // ( reverse )? qq10 : qq20;
// TDLog.Debug( "snap setting area FIRST null ");
} else {
// TDLog.Debug( "snap start prev " + prev.mX + " " + prev.mY );
LinePoint q = prev;
while ( prev != null && prev != next ) {
q = prev;
prev = q.mPrev;
}
area.mFirst = q;
if ( q.mPrev != null ) { // make sure first has no prev
q.mPrev.mNext = null;
q.mPrev = null;
}
// TDLog.Debug( "snap setting area FIRST " + area.mFirst.mX + " " + area.mFirst.mY );
}
if ( next == null ) {
area.mLast = null; // ( reverse )? qq20 : qq10;
// TDLog.Debug( "snap setting area LAST null ");
} else {
// TDLog.Debug( "snap start next " + next.mX + " " + next.mY );
LinePoint q = next;
while ( next != null && next != prev ) {
q = next;
next = q.mNext;
}
area.mLast = q;
if ( q.mNext != null ) {
q.mNext.mPrev = null;
q.mNext = null;
}
// TDLog.Debug( "snap setting area LAST " + area.mLast.mX + " " + area.mLast.mY );
}
next = (reverse)? qq20 : qq10;
// insert points pp20 - ... - pp10 (included)
if ( reverse ) {
LinePoint q = qq10.mPrev;
LinePoint p = pp10;
if ( q != null ) {
// TDLog.Debug( "snap attach at " + q.mX + " " + q.mY );
} else {
// TDLog.Debug( "snap restart area ");
}
q = new LinePoint( p.mX, p.mY, q );
// TDLog.Debug( "snap first new point " + q.mX + " " + q.mY );
if ( p != pp20 ) {
p = p.mPrev;
if ( area.mFirst == null ) area.mFirst = q;
for ( ; p != null && p != pp20; p = p.mPrev ) {
if ( p.has_cp && p != pp10 ) {
LinePoint pp = p.mNext;
q = new LinePoint( pp.mX2, pp.mY2, pp.mX1, pp.mY1, p.mX, p.mY, q );
} else {
q = new LinePoint( p.mX, p.mY, q );
}
// TDLog.Debug( "snap new point " + q.mX + " " + q.mY );
}
if ( p != null ) { // FIXME add last point
if ( p.has_cp ) {
LinePoint pp = p.mNext;
q = new LinePoint( pp.mX2, pp.mY2, pp.mX1, pp.mY1, p.mX, p.mY, q );
} else {
q = new LinePoint( p.mX, p.mY, q );
}
// TDLog.Debug( "snap last new point " + q.mX + " " + q.mY );
}
}
q.mNext = next;
if ( next != null ) {
next.mPrev = q;
next.has_cp = false; // enforce straight segment
}
if ( area.mLast == null ) area.mLast = q;
} else { // not reverse
LinePoint q = qq20.mPrev;
LinePoint p = pp20;
if ( q != null ) {
// TDLog.Debug( "snap attach at " + q.mX + " " + q.mY );
} else {
// TDLog.Debug( "snap restart area ");
}
q = new LinePoint( p.mX, p.mY, q );
// TDLog.Debug( "snap first new point " + q.mX + " " + q.mY );
if ( p != pp10 ) {
p = p.mNext;
if ( area.mFirst == null ) area.mFirst = q;
for ( ; p != null && p != pp10; p = p.mNext ) {
q = new LinePoint( p, q );
// TDLog.Debug( "snap new point " + q.mX + " " + q.mY );
}
// if ( p != null ) { // FIXME not add "last" point
// q = new LinePoint( p, q );
// TDLog.Debug( "snap last new point " + q.mX + " " + q.mY );
// }
}
q.mNext = next;
if ( next != null ) {
next.mPrev = q;
next.has_cp = false;
}
if ( area.mLast == null ) area.mLast = q;
}
area.recount();
// TDLog.Debug( "snap new size " + area.size() );
}
// area.mPoints = pts2;
area.retracePath();
if ( ret == 0 ) {
synchronized( mSelection ) {
mSelection.insertPath( area );
}
}
clearSelected();
}
// checkLines();
return ret;
}
SelectionPoint hotItem() { return mSelected.mHotItem; }
void rotateHotItem( float dy )
{
synchronized( mSelection ) {
mSelected.rotateHotItem( dy );
}
}
// void shiftHotItem( float dx, float dy, float range )
void shiftHotItem( float dx, float dy )
{
synchronized( mSelection ) {
// SelectionPoint sp = mSelected.shiftHotItem( dx, dy, range );
SelectionPoint sp = mSelected.shiftHotItem( dx, dy );
DrawingPath path = sp.mItem;
// if ( path.mType == DrawingPath.DRAWING_PATH_POINT || DrawingWindow.mEditRadius == 0 ) {
// mSelection.checkBucket( sp );
// } else {
// mSelection.rebucketLinePath( (DrawingPointLinePath)path );
// }
mSelection.checkBucket( sp );
}
}
SelectionPoint nextHotItem() { return mSelected.nextHotItem(); }
SelectionPoint prevHotItem() { return mSelected.prevHotItem(); }
// used by flipProfile
// void rebuildSelection()
// {
// Selection selection = new Selection();
// synchronized ( mCurrentStack ) {
// final Iterator i = mCurrentStack.iterator();
// while ( i.hasNext() ) {
// final ICanvasCommand cmd = (ICanvasCommand) i.next();
// if ( cmd.commandType() != 0 ) continue;
// DrawingPath path = (DrawingPath) cmd;
// selection.insertPath( path );
// // switch ( path.mType ) {
// // case DrawingPath.DRAWING_PATH_POINT:
// // case DrawingPath.DRAWING_PATH_LINE;
// // case DrawingPath.DRAWING_PATH_AREA:
// // selection.insertPath( path );
// // break;
// // }
// }
// }
// mSelection = selection;
// }
RectF computeBBox()
{
float xmin=1000000f, xmax=-1000000f,
ymin=1000000f, ymax=-1000000f;
synchronized( mCurrentStack ) {
final Iterator i = mCurrentStack.iterator();
while ( i.hasNext() ) {
final ICanvasCommand cmd = (ICanvasCommand) i.next();
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
// RectF bbox = p.mBBox;
if ( p.left < xmin ) xmin = p.left;
if ( p.right > xmax ) xmax = p.right;
if ( p.top < ymin ) ymin = p.top;
if ( p.bottom > ymax ) ymax = p.bottom;
}
}
return new RectF( xmin, ymin, xmax, ymax ); // left top right bottom
}
// FIXME DataHelper and SID are necessary to export splays by the station
public void exportTherion( // DataHelper dh, long sid,
int type, BufferedWriter out, String scrap_name, String proj_name, int proj_dir )
{
RectF bbox = computeBBox();
DrawingIO.exportTherion( // dh, sid,
type, out, scrap_name, proj_name, proj_dir, bbox, mNorthLine,
mCurrentStack, mUserStations, mStations, mSplaysStack );
}
public void exportDataStream( int type, DataOutputStream dos, String scrap_name, int proj_dir )
{
RectF bbox = computeBBox();
DrawingIO.exportDataStream( type, dos, scrap_name, proj_dir, bbox, mNorthLine, mCurrentStack, mUserStations, mStations );
}
void exportAsCsx( PrintWriter pw, String cave, String branch )
{
synchronized( mCurrentStack ) {
pw.format(" <layers>\n");
// LAYER 0: images and sketches
pw.format(" <layer name=\"Base\" type=\"0\">\n");
pw.format(" <items>\n");
pw.format(" </items>\n");
pw.format(" </layer>\n");
// LAYER 1: soil areas
pw.format(" <layer name=\"Soil\" type=\"1\">\n");
pw.format(" <items>\n");
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
if ( p.mType == DrawingPath.DRAWING_PATH_AREA ) {
DrawingAreaPath ap = (DrawingAreaPath)p;
if ( BrushManager.getAreaCsxLayer( ap.mAreaType ) != 1 ) continue;
ap.toCsurvey( pw, cave, branch );
}
}
pw.format(" </items>\n");
pw.format(" </layer>\n");
// LAYER 2:
pw.format(" <layer name=\"Water and floor morphologies\" type=\"2\">\n");
pw.format(" <items>\n");
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
if ( p.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath lp = (DrawingLinePath)p;
if ( BrushManager.getLineCsxLayer( lp.mLineType ) != 2 ) continue;
lp.toCsurvey( pw, cave, branch );
} else if ( p.mType == DrawingPath.DRAWING_PATH_AREA ) {
DrawingAreaPath ap = (DrawingAreaPath)p;
if ( BrushManager.getAreaCsxLayer( ap.mAreaType ) != 2 ) continue;
ap.toCsurvey( pw, cave, branch );
}
}
pw.format(" </items>\n");
pw.format(" </layer>\n");
// LAYER 3
pw.format(" <layer name=\"Rocks and concretions\" type=\"3\">\n");
pw.format(" <items>\n");
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
if ( p.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath lp = (DrawingLinePath)p;
if ( BrushManager.getLineCsxLayer( lp.mLineType ) != 2 ) continue;
lp.toCsurvey( pw, cave, branch );
}
}
pw.format(" </items>\n");
pw.format(" </layer>\n");
// LAYER 4
pw.format(" <layer name=\"Ceiling morphologies\" type=\"4\">\n");
pw.format(" <items>\n");
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
if ( p.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath lp = (DrawingLinePath)p;
if ( BrushManager.getLineCsxLayer( lp.mLineType ) != 4 ) continue;
lp.toCsurvey( pw, cave, branch );
}
}
pw.format(" </items>\n");
pw.format(" </layer>\n");
// LAYER 5:
pw.format(" <layer name=\"Borders\" type=\"5\">\n");
pw.format(" <items>\n");
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
if ( p.mType == DrawingPath.DRAWING_PATH_LINE ) {
DrawingLinePath lp = (DrawingLinePath)p;
if ( BrushManager.getLineCsxLayer( lp.mLineType ) != 5 ) continue;
lp.toCsurvey( pw, cave, branch );
}
// if ( lp.lineType() == BrushManager.mLineLib.mLineWallIndex ) {
// // linetype: 0 line, 1 spline, 2 bezier
// pw.format(" <item layer=\"5\" name=\"\" type=\"4\" category=\"1\" linetype=\"0\" mergemode=\"0\">\n");
// pw.format(" <pen type=\"1\" />\n");
// pw.format(" <points data=\"");
// ArrayList< LinePoint > pts = lp.mPoints;
// boolean b = true;
// for ( LinePoint pt : pts ) {
// float x = DrawingWindow.sceneToWorldX( pt.mX );
// float y = DrawingWindow.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");
// }
}
pw.format(" </items>\n");
pw.format(" </layer>\n");
// LAYER 6: signs and texts
pw.format(" <layer name=\"Signs\" type=\"6\">\n");
pw.format(" <items>\n");
for ( ICanvasCommand cmd : mCurrentStack ) {
if ( cmd.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath) cmd;
if ( p.mType == DrawingPath.DRAWING_PATH_POINT ) {
DrawingPointPath pp = (DrawingPointPath)p;
if ( BrushManager.getPointCsxLayer( pp.mPointType ) != 6 ) continue;
pp.toCsurvey( pw, cave, branch );
}
}
pw.format(" </items>\n");
pw.format(" </layer>\n");
pw.format(" </layers>\n");
}
}
// called by DrawingSurface::addDrawingStationName
public void addStation( DrawingStationName st, boolean selectable )
{
// Log.v("DistoX", "add station " + st.mName + " scene " + st.cx + " " + st.cy + " XSection " + st.mXSectionType );
synchronized( mStations ) {
mStations.add( st );
if ( selectable ) {
synchronized( mSelection ) {
// Log.v( "DistoX", "selection add station " + st.mName );
mSelection.insertStationName( st );
}
}
}
}
// this is not efficient: the station names should be stored in a tree (key = name) for log-time search
// type = type of the plot
void setStationXSections( List<PlotInfo> xsections, long type )
{
for ( DrawingStationName st : mStations ) {
String name = st.mName;
// Log.v( "DistoX", "Station <" + name + ">" );
for ( PlotInfo plot : xsections ) {
if ( name.equals( plot.start ) ) {
st.setXSection( plot.azimuth, plot.clino, type );
break;
}
}
}
}
float computeSectionArea()
{
float ret = 0;
for ( ICanvasCommand icc : mCurrentStack ) {
if ( icc.commandType() != 0 ) continue;
DrawingPath p = (DrawingPath)icc;
if ( p.mType != DrawingPath.DRAWING_PATH_LINE ) continue;
DrawingLinePath lp = (DrawingLinePath)p;
if ( lp.mLineType != BrushManager.mLineLib.mLineWallIndex ) continue;
LinePoint pt = lp.mFirst;
while ( pt != lp.mLast ) {
LinePoint pn = pt.mNext;
ret += pt.mY * pn.mX - pt.mX * pn.mY;
pt = pn;
}
}
return ret / 2;
}
}