@@ -676,7 +676,7 @@ public synchronized Path[] getPathsStructured() {
676676 public Collection <Tree > getTrees () {
677677 final HashMap <String , Tree > map = new HashMap <>();
678678 allPaths .forEach (p ->{
679- final Path pathToUse = ( p . getUseFitted ()) ? p . getFitted () : p ;
679+ final Path pathToUse = getVersionInUse ( p ) ;
680680 String treeID = pathToUse .getTreeLabel ();
681681 if (map .get (treeID ) == null ) {
682682 final Tree tree = new Tree ();
@@ -704,7 +704,7 @@ public Collection<Tree> getTrees() {
704704 public Tree getTree (final String treeLabel ) {
705705 final Tree tree = new Tree ();
706706 allPaths .forEach (p ->{
707- final Path pathToUse = ( p . getUseFitted ()) ? p . getFitted () : p ;
707+ final Path pathToUse = getVersionInUse ( p ) ;
708708 if (treeLabel .equals (pathToUse .getTreeLabel ()))
709709 tree .add (pathToUse );
710710 });
@@ -724,7 +724,7 @@ public Tree getTree(final String treeLabel) {
724724 public Tree getTree (final int treeId ) {
725725 final Tree tree = new Tree ();
726726 allPaths .forEach (p ->{
727- final Path pathToUse = ( p . getUseFitted ()) ? p . getFitted () : p ;
727+ final Path pathToUse = getVersionInUse ( p ) ;
728728 if (treeId == pathToUse .getTreeID ())
729729 tree .add (pathToUse );
730730 });
@@ -1971,9 +1971,7 @@ private void addImportedPathsTo3DViewer() {
19711971 // never registered) is itself the de facto path and must still be added
19721972 if (!isDeFactoPath (p ) || p .size () < 2 )
19731973 continue ;
1974- Path pathToAdd ;
1975- if (p .getUseFitted ()) pathToAdd = p .getFitted ();
1976- else pathToAdd = p ;
1974+ final Path pathToAdd = p .getVersionInUse ();
19771975 pathToAdd .addTo3DViewer (plugin .univ , SNTPrefs .deselectedPathColor (), plugin .colorImage );
19781976 }
19791977 }
@@ -2015,6 +2013,7 @@ public void endElement(final String uri, final String localName,
20152013 final Integer fittedID = fittedFields .get (p .getID ());
20162014 final Integer fittedVersionOfID = fittedVersionOfFields .get (p .getID ());
20172015 final Boolean useFitted = useFittedFields .get (p .getID ());
2016+ boolean fitDiscarded = false ;
20182017
20192018 if (startID != null ) {
20202019 final Path startPath = getPathFromID (startID );
@@ -2056,6 +2055,20 @@ public void endElement(final String uri, final String localName,
20562055
20572056 pReversed .setBranchFrom (endPath , endJoinPoint );
20582057
2058+ // reversed() does not carry over the fit: discard it (and its
2059+ // registration) so that no dangling fitted links remain
2060+ if (fittedID != null ) {
2061+ final Path fit = getPathFromID (fittedID );
2062+ if (fit != null ) {
2063+ allPaths .remove (fit );
2064+ pathIdMap .remove (fit .getID (), fit );
2065+ pathNameMap .remove (fit .getName (), fit );
2066+ }
2067+ fitDiscarded = true ;
2068+ SNTUtils .log ("End-joined path " + p .getID () + " ('" + p .getName ()
2069+ + "') was fitted: fit discarded" );
2070+ }
2071+
20592072 for (final Path join : new ArrayList <>(p .connectedPaths )) {
20602073 if (join .getParentPath () == p ) {
20612074 final PointInImage joinPoint = join .getBranchPoint ();
@@ -2065,9 +2078,16 @@ public void endElement(final String uri, final String localName,
20652078 }
20662079 } // end null-check else
20672080 }
2068- if (fittedID != null ) {
2069- p .fitted = getPathFromID (fittedID );
2070- p .setUseFitted (useFitted );
2081+ if (fittedID != null && !fitDiscarded ) {
2082+ final Path fit = getPathFromID (fittedID );
2083+ if (fit == null ) {
2084+ SNTUtils .log ("Malformed traces file: fitted=" + fittedID
2085+ + " referenced by path " + p .getID () + " ('" + p .getName ()
2086+ + "') does not exist. Fit skipped." );
2087+ } else {
2088+ p .fitted = fit ;
2089+ p .setUseFitted (useFitted );
2090+ }
20712091 }
20722092 if (fittedVersionOfID != null ) {
20732093 p .fittedVersionOf = getPathFromID (fittedVersionOfID );
@@ -2092,10 +2112,6 @@ else if (p != p.fittedVersionOf.getFitted())
20922112 throw new TracesFileFormatException (
20932113 "Malformed traces file: p didn't match p.fittedVersionOf.fitted" );
20942114 }
2095- else if (p .getUseFitted ()) {
2096- throw new TracesFileFormatException (
2097- "Malformed traces file: p.useFitted was true but p.fitted was null" );
2098- }
20992115 }
21002116
21012117 // allPaths have been used to store all imported paths, including fitted ones.
@@ -3156,10 +3172,7 @@ synchronized void setPathPointsInVolume(final Collection<Path> paths,
31563172 for (final Path topologyPath : paths ) {
31573173 if (pixelIntensity == -1 )
31583174 actualPixelIntensity = (short ) ++label ;
3159- Path p = topologyPath ;
3160- if (topologyPath .getUseFitted ()) {
3161- p = topologyPath .getFitted ();
3162- }
3175+ final Path p = topologyPath .getVersionInUse ();
31633176 final int n = p .size ();
31643177
31653178 final ArrayList <Bresenham3D .IntegerPoint > pointsToJoin =
@@ -3266,7 +3279,8 @@ public synchronized NodeRef nearestNodeOnPaths(final Collection<Path> paths, fin
32663279
32673280 /**
32683281 * Returns the version of a path that is in use, i.e., the one that is displayed and analyzed: its fitted
3269- * flavor if {@link Path#getUseFitted()}, otherwise the path itself. Same rule as {@link Tree#Tree(Collection)}.
3282+ * flavor if {@link Path#getUseFitted()}, otherwise the path itself. Same rule as
3283+ * {@link Tree#Tree(Collection)}, which uses the collection itself as registry.
32703284 * A fitted copy whose original is registered with this manager is first resolved to that original (see
32713285 * {@link #isDeFactoPath(Path)}), so that both flavors of a path always resolve to the same version.
32723286 *
@@ -3276,7 +3290,7 @@ public synchronized NodeRef nearestNodeOnPaths(final Collection<Path> paths, fin
32763290 public synchronized Path getVersionInUse (final Path p ) {
32773291 if (p == null ) return null ;
32783292 final Path base = (p .isFittedVersionOfAnotherPath () && !isDeFactoPath (p )) ? p .getUnfitted () : p ;
3279- return base .getUseFitted () ? base . getFitted () : base ;
3293+ return base .getVersionInUse () ;
32803294 }
32813295
32823296 /**
@@ -3680,10 +3694,7 @@ public void exportToCSV(final File outputFile) throws IOException {
36803694 }
36813695 pw .print ("\r \n " );
36823696 for (final Path p : allPaths ) {
3683- Path pForLengthAndName = p ;
3684- if (p .getUseFitted ()) {
3685- pForLengthAndName = p .getFitted ();
3686- }
3697+ final Path pForLengthAndName = p .getVersionInUse ();
36873698 if (p .fittedVersionOf != null ) continue ;
36883699 SNTUtils .csvQuoteAndPrint (pw , p .getID ()); //col1: PathID
36893700 pw .print ("," );
@@ -3766,7 +3777,7 @@ protected void update3DViewerContents() {
37663777
37673778 // If path is being rendered with its own custom color, highlight it
37683779 // somehow if is being selected
3769- if ( p . getUseFitted ()) p = p .getFitted ();
3780+ p = p .getVersionInUse ();
37703781 if (p .content3D != null ) p .content3D .setShaded (!(customColor &&
37713782 selected ));
37723783
0 commit comments