/* @file Selection.java * * @author marco corvi * @date feb 2013 * * @brief Selection among drawing items * -------------------------------------------------------- * Copyright This sowftare is distributed under GPL-3.0 or later * See the file COPYING. * ---------------------------------------------------- */ package com.topodroid.DistoX; // import java.util.LinkedList; // import java.util.ListIterator; import java.util.ArrayList; import java.util.Iterator; import android.util.Log; class Selection { final static int BSIZE = 100; // bucket size factor ArrayList< SelectionPoint > mPoints; ArrayList< SelectionBucket > mBuckets; Selection( ) { mPoints = new ArrayList< SelectionPoint >(); mBuckets = new ArrayList< SelectionBucket >(); } void shiftSelectionBy( float x, float y ) { for ( SelectionPoint sp : mPoints ) { int t = sp.type(); if ( t == DrawingPath.DRAWING_PATH_POINT || t == DrawingPath.DRAWING_PATH_LINE || t == DrawingPath.DRAWING_PATH_AREA ) { sp.shiftSelectionBy(x, y); float x1 = sp.X(); float y1 = sp.Y(); if ( sp.mBucket != null ) { if ( ! sp.mBucket.contains( x1, y1 ) ) { sp.setBucket( getBucket( x1, y1 ) ); } } else { sp.setBucket( getBucket( x1, y1 ) ); } } } } void clearSelectionPoints() { // Log.v("DistoX", "Selection clear" ); mPoints.clear(); mBuckets.clear(); } void clearReferencePoints() { synchronized ( mPoints ) { Iterator< SelectionPoint > it = mPoints.iterator(); while( it.hasNext() ) { SelectionPoint sp1 = (SelectionPoint)it.next(); if ( sp1.isReferenceType() ) { sp1.setBucket( null ); it.remove( ); } } } } void clearDrawingPoints() { synchronized ( mPoints ) { Iterator< SelectionPoint > it = mPoints.iterator(); while( it.hasNext() ) { SelectionPoint sp1 = (SelectionPoint)it.next(); if ( sp1.isDrawingType() ) { sp1.setBucket( null ); it.remove( ); } } } } void insertStationName( DrawingStationName st ) { insertItem( st, null ); } /** like insertItem, but it returns the inserted SelectionPoint * @param path point-line path * @param point new point on the point-line * @return */ SelectionPoint insertPathPoint( DrawingPointLinePath path, LinePoint pt ) { SelectionPoint sp = new SelectionPoint( path, pt, null ); mPoints.add( sp ); sp.setBucket( getBucket( sp.X(), sp.Y() ) ); // Log.v("DistoX", "Selection insert path point " + pt.mX + " " + pt.mY ); // sp.mBucket.dump(); return sp; } void insertLinePath( DrawingLinePath path ) { for ( LinePoint p2 = path.mFirst; p2 != null; p2 = p2.mNext ) { insertItem( path, p2 ); } } void insertPath( DrawingPath path ) { // Log.v("DistoX", "Selection insert path" ); // LinePoint p1; LinePoint p2; switch ( path.mType ) { case DrawingPath.DRAWING_PATH_FIXED: case DrawingPath.DRAWING_PATH_SPLAY: insertItem( path, null ); break; case DrawingPath.DRAWING_PATH_GRID: // nothing break; case DrawingPath.DRAWING_PATH_STATION: insertItem( path, null ); break; case DrawingPath.DRAWING_PATH_POINT: insertItem( path, null ); break; case DrawingPath.DRAWING_PATH_LINE: DrawingLinePath lp = (DrawingLinePath)path; for ( p2 = lp.mFirst; p2 != null; p2 = p2.mNext ) { insertItem( path, p2 ); } break; case DrawingPath.DRAWING_PATH_AREA: DrawingAreaPath ap = (DrawingAreaPath)path; for ( p2 = ap.mFirst; p2 != null; p2 = p2.mNext ) { insertItem( path, p2 ); } break; default: } } void resetDistances() { // Log.v("DistoX", "Selection reset distances" ); for ( SelectionPoint pt : mPoints ) { pt.mDistance = 0.0f; } } void rebucket( SelectionPoint sp ) { sp.setBucket( getBucket( sp.X(), sp.Y() ) ); } private void insertItem( DrawingPath path, LinePoint pt ) { SelectionPoint sp = new SelectionPoint( path, pt, null ); mPoints.add( sp ); sp.setBucket( getBucket( sp.X(), sp.Y() ) ); // if ( pt != null ) { // Log.v("DistoX", "insert item path type " + path.mType + " pt " + pt.mX + " " + pt.mY ); // } else { // Log.v("DistoX", "insert item path type " + path.mType + " null pt "); // } // sp.mBucket.dump(); // dumpBuckets(); } // FIXME this is called with dmin = 10f SelectionPoint getBucketNearestPoint( SelectionPoint sp, float x, float y, float dmin ) { SelectionPoint spmin = null; float x0 = sp.X(); float y0 = sp.Y(); for ( SelectionBucket bucket : mBuckets ) { if ( bucket.contains( x0, y0, dmin, dmin ) ) { final Iterator jt = bucket.mPoints.iterator(); while( jt.hasNext() ) { SelectionPoint sp2 = (SelectionPoint)jt.next(); if ( sp == sp2 ) continue; float d = sp2.distance( x, y ); if ( d < dmin ) { dmin = d; spmin = sp2; } } } } return spmin; } SelectionPoint getNearestPoint( SelectionPoint sp, float x, float y, float dmin ) { SelectionPoint spmin = getBucketNearestPoint( sp, x, y, dmin ); if ( spmin != null ) return spmin; final Iterator it = mPoints.iterator(); while( it.hasNext() ) { SelectionPoint sp1 = (SelectionPoint)it.next(); if ( sp == sp1 ) continue; float d = sp1.distance( x, y ); if ( d < dmin ) { dmin = d; spmin = sp1; } } return spmin; } void removePoint( SelectionPoint sp ) { sp.setBucket( null ); mPoints.remove( sp ); } void removePath( DrawingPath path ) { if ( path.mType == DrawingPath.DRAWING_PATH_LINE || path.mType == DrawingPath.DRAWING_PATH_AREA ) { DrawingPointLinePath line = (DrawingPointLinePath)path; for ( LinePoint lp = line.mFirst; lp != null; lp = lp.mNext ) { for ( SelectionPoint sp : mPoints ) { if ( sp.mPoint == lp ) { removePoint( sp ); break; } } } } else if ( path.mType == DrawingPath.DRAWING_PATH_POINT ) { for ( SelectionPoint sp : mPoints ) { if ( sp.mItem == path ) { removePoint( sp ); break; } } } } void removeLinePoint( DrawingPointLinePath path, LinePoint lp ) { if ( path.mType != DrawingPath.DRAWING_PATH_LINE && path.mType != DrawingPath.DRAWING_PATH_AREA ) return; for ( SelectionPoint sp : mPoints ) { if ( sp.mPoint == lp ) { removePoint( sp ); return; } } } SelectionPoint getSelectionPoint( LinePoint lp ) { // for ( SelectionPoint sp : mPoints ) { // if ( sp.mPoint == lp ) return sp; // } // return null; // FIXED use buckets float x0 = lp.mX; float y0 = lp.mY; for ( SelectionBucket bucket : mBuckets ) { if ( bucket.contains( x0, y0, 10f, 10f ) ) { final Iterator jt = bucket.mPoints.iterator(); while( jt.hasNext() ) { SelectionPoint sp = (SelectionPoint)jt.next(); if ( lp == sp.mPoint ) return sp; } } } return null; } SelectionPoint bucketSelectOnItemAt( DrawingPath item, float x, float y, float radius ) { float min_distance = radius; SelectionPoint ret = null; for ( SelectionBucket bucket : mBuckets ) { if ( bucket.contains( x, y, radius, radius ) ) { for ( SelectionPoint sp : bucket.mPoints ) { if ( sp.mItem == item ) { float d = sp.distance( x, y ); if ( d < min_distance ) { min_distance = d; ret = sp; } } } } } return ret; } void bucketSelectAt( float x, float y, float radius, SelectionSet sel, boolean legs, boolean splays, boolean stations ) { // Log.v("DistoX", "bucket select at " + x + " " + y + " R " + radius + " buckets " + mBuckets.size() ); for ( SelectionBucket bucket : mBuckets ) { // bucket.dump(); if ( bucket.contains( x, y, radius, radius ) ) { for ( SelectionPoint sp : bucket.mPoints ) { if ( !legs && sp.type() == DrawingPath.DRAWING_PATH_FIXED ) continue; if ( !splays && sp.type() == DrawingPath.DRAWING_PATH_SPLAY ) continue; if ( !stations && ( sp.type() == DrawingPath.DRAWING_PATH_STATION || sp.type() == DrawingPath.DRAWING_PATH_NAME ) ) continue; sp.mDistance = sp.distance( x, y ); if ( sp.mDistance < radius ) { sel.addPoint( sp ); // sp.mBucket.dump(); } } } } } SelectionPoint selectOnItemAt( DrawingPath item, float x, float y, float radius ) { return bucketSelectOnItemAt( item, x, y, radius ); } void selectAt( SelectionSet sel, float x, float y, float radius, boolean legs, boolean splays, boolean stations ) { // Log.v( "DistoX", "selection select at " + x + " " + y + " pts " + mPoints.size() + " " + legs + " " + splays + " " + stations + " radius " + radius ); bucketSelectAt( x, y, radius, sel, legs, splays, stations ); // Log.v("DistoX", "bucketSelect size " + sel.size() ); if ( sel.size() > 0 ) return; // for ( SelectionPoint sp : mPoints ) { // if ( !legs && sp.type() == DrawingPath.DRAWING_PATH_FIXED ) continue; // if ( !splays && sp.type() == DrawingPath.DRAWING_PATH_SPLAY ) continue; // if ( !stations && ( sp.type() == DrawingPath.DRAWING_PATH_STATION || sp.type() == DrawingPath.DRAWING_PATH_NAME ) ) continue; // sp.mDistance = sp.distance(x, y); // // Log.v("DistoX", "sp " + sp.name() + " distance " + sp.mDistance ); // if ( sp.mDistance < radius ) { // sel.addPoint( sp ); // } // } } private SelectionBucket getBucket( float x, float y ) { for ( SelectionBucket bucket : mBuckets ) { if ( bucket.contains( x, y ) ) return bucket; } float x0 = BSIZE * (float)Math.floor(x / BSIZE); float y0 = BSIZE * (float)Math.floor(y / BSIZE); SelectionBucket ret = new SelectionBucket( x0, y0, x0+BSIZE, y0+BSIZE ); mBuckets.add( ret ); return ret; } // check if the SelectionPoint is still in its bucket // otherwise move it to the new bucket void checkBucket( SelectionPoint sp ) { if ( sp == null ) return; if ( sp.mLP1 != null || sp.mLP2 != null ) { rebucketLinePath( (DrawingPointLinePath)sp.mItem ); } else { SelectionBucket sb = sp.mBucket; if ( sb != null && ! sb.contains( sp.X(), sp.Y() ) ) { // find the bucket that contains sp and assign it to sp sb = getBucket( sp.X(), sp.Y() ); sp.setBucket( sb ); // this removes sp from its old bucket and add it to the new bucket } } } void rebucketLinePath( DrawingPointLinePath line ) { for ( LinePoint lp = line.mFirst; lp != null; lp = lp.mNext ) { for ( SelectionPoint sp : mPoints ) { if ( sp.mPoint == lp ) { SelectionBucket sb = sp.mBucket; if ( sb != null && ! sb.contains( sp.X(), sp.Y() ) ) { // find the bucket that contains sp and assign it to sp sb = getBucket( sp.X(), sp.Y() ); sp.setBucket( sb ); // this removes sp from its old bucket and add it to the new bucket } break; } } } } // private void dumpBuckets() // { // for ( SelectionBucket bucket : mBuckets ) { // bucket.dump(); // } // } // private void dumpPointsTypes() // { // int nfxd = 0; // int nspl = 0; // int ngrd = 0; // int nsta = 0; // int npnt = 0; // int nlin = 0; // int nare = 0; // int nnam = 0; // int nnrt = 0; // int noth = 0; // for ( SelectionPoint p : mPoints ) { // switch ( p.mItem.mType ) { // case DrawingPath.DRAWING_PATH_FIXED: nfxd++; break; // case DrawingPath.DRAWING_PATH_SPLAY: nspl++; break; // case DrawingPath.DRAWING_PATH_GRID: ngrd++; break; // case DrawingPath.DRAWING_PATH_STATION: nsta++; break; // case DrawingPath.DRAWING_PATH_POINT: npnt++; break; // case DrawingPath.DRAWING_PATH_LINE: nlin++; break; // case DrawingPath.DRAWING_PATH_AREA: nare++; break; // case DrawingPath.DRAWING_PATH_NAME: nnam++; break; // case DrawingPath.DRAWING_PATH_NORTH: nnrt++; break; // default: noth ++; // } // } // Log.v("DistoX", "Selection points " + mPoints.size() + " " + nfxd + " " + nspl + " " + ngrd + " " + nsta // + " " + npnt + " " + nlin + " " + nare + " " + nnam + " " + nnrt + " " + noth ); // } }