private OsmTrack findTrackHelper(final String operationName, final MatchedWaypoint startWp, final MatchedWaypoint endWp, final OsmTrack costCuttingTrack, final OsmTrack refTrack, boolean fastPartialRecalc) {
        int maxTotalCost = guideTrack != null ? guideTrack.cost + 5000 : 1000000000;
        int firstMatchCost = 1000000000;

        logInfo("findtrack with airDistanceCostFactor=" + airDistanceCostFactor);
        if (costCuttingTrack != null) {
            logInfo("costCuttingTrack.cost=" + costCuttingTrack.cost);
        }

        matchPath = null;
        int nodesVisited = 0;

        final long startNodeId1 = startWp.node1.getIdFromPos();
        final long startNodeId2 = startWp.node2.getIdFromPos();
        final long endNodeId1 = endWp == null ? -1L : endWp.node1.getIdFromPos();
        final long endNodeId2 = endWp == null ? -1L : endWp.node2.getIdFromPos();
        OsmNode end1 = null;
        OsmNode end2 = null;
        OsmNodeNamed endPos = null;

        boolean sameSegmentSearch = false;
        final OsmNode start1 = nodesCache.getGraphNode(startWp.node1);
        final OsmNode start2 = nodesCache.getGraphNode(startWp.node2);
        if (endWp != null) {
            end1 = nodesCache.getGraphNode(endWp.node1);
            end2 = nodesCache.getGraphNode(endWp.node2);
            nodesCache.nodesMap.endNode1 = end1;
            nodesCache.nodesMap.endNode2 = end2;
            endPos = new OsmNodeNamed(endWp.crosspoint);
            sameSegmentSearch = (start1 == end1 && start2 == end2) || (start1 == end2 && start2 == end1);
        }
        if (!nodesCache.obtainNonHollowNode(start1)) {
            return null;
        }
        nodesCache.expandHollowLinkTargets(start1);
        if (!nodesCache.obtainNonHollowNode(start2)) {
            return null;
        }
        nodesCache.expandHollowLinkTargets(start2);


        routingContext.startDirectionValid = routingContext.forceUseStartDirection || fastPartialRecalc;
        routingContext.startDirectionValid &= routingContext.startDirection != null && !routingContext.inverseDirection;
        if (routingContext.startDirectionValid) {
            logInfo("using start direction " + routingContext.startDirection);
        }

        final OsmPath startPath1 = getStartPath(start1, start2, startWp, endPos, sameSegmentSearch);
        final OsmPath startPath2 = getStartPath(start2, start1, startWp, endPos, sameSegmentSearch);

        // check for an INITIAL match with the cost-cutting-track
        if (costCuttingTrack != null) {
            final OsmPathElement pe1 = costCuttingTrack.getLink(startNodeId1, startNodeId2);
            if (pe1 != null) {
                logInfo("initialMatch pe1.cost=" + pe1.cost);
                int c = startPath1.cost - pe1.cost;
                if (c < 0) {
                    c = 0;
                }
                if (c < firstMatchCost) {
                    firstMatchCost = c;
                }
            }

            final OsmPathElement pe2 = costCuttingTrack.getLink(startNodeId2, startNodeId1);
            if (pe2 != null) {
                logInfo("initialMatch pe2.cost=" + pe2.cost);
                int c = startPath2.cost - pe2.cost;
                if (c < 0) {
                    c = 0;
                }
                if (c < firstMatchCost) {
                    firstMatchCost = c;
                }
            }

            if (firstMatchCost < 1000000000) {
                logInfo("firstMatchCost from initial match=" + firstMatchCost);
            }
        }

        synchronized (openSet) {
            openSet.clear();
            addToOpenset(startPath1);
            addToOpenset(startPath2);
        }
        final List<OsmPath> openBorderList = new ArrayList<>(4096);
        boolean memoryPanicMode = false;
        boolean needNonPanicProcessing = false;

        for (; ; ) {
            if (terminated) {
                throw new IllegalArgumentException("operation killed by thread-priority-watchdog after " + (System.currentTimeMillis() - startTime) / 1000 + " seconds");
            }

            if (maxRunningTime > 0) {
                final long timeout = (matchPath == null && fastPartialRecalc) ? maxRunningTime / 3 : maxRunningTime;
                if (System.currentTimeMillis() - startTime > timeout) {
                    throw new IllegalArgumentException(operationName + " timeout after " + (timeout / 1000) + " seconds");
                }
            }

            synchronized (openSet) {

                final OsmPath path = openSet.popLowestKeyValue();
                if (path == null) {
                    if (openBorderList.isEmpty()) {
                        break;
                    }
                    for (OsmPath p : openBorderList) {
                        openSet.add(p.cost + (int) (p.airdistance * airDistanceCostFactor), p);
                    }
                    openBorderList.clear();
                    memoryPanicMode = false;
                    needNonPanicProcessing = true;
                    continue;
                }

                if (path.airdistance == -1) {
                    continue;
                }

                if (directWeaving && nodesCache.hasHollowLinkTargets(path.getTargetNode())) {
                    if (!memoryPanicMode && !nodesCache.nodesMap.isInMemoryBounds(openSet.getSize(), false)) {
                        final int nodesBefore = nodesCache.nodesMap.nodesCreated;
                        final int pathsBefore = openSet.getSize();

                        nodesCache.nodesMap.collectOutreachers();
                        for (; ; ) {
                            final OsmPath p3 = openSet.popLowestKeyValue();
                            if (p3 == null) {
                                break;
                            }
                            if (p3.airdistance != -1 && nodesCache.nodesMap.canEscape(p3.getTargetNode())) {
                                openBorderList.add(p3);
                            }
                        }
                        nodesCache.nodesMap.clearTemp();
                        for (OsmPath p : openBorderList) {
                            openSet.add(p.cost + (int) (p.airdistance * airDistanceCostFactor), p);
                        }
                        openBorderList.clear();
                        logInfo("collected, nodes/paths before=" + nodesBefore + "/" + pathsBefore + " after=" + nodesCache.nodesMap.nodesCreated + "/" + openSet.getSize() + " maxTotalCost=" + maxTotalCost);
                        if (!nodesCache.nodesMap.isInMemoryBounds(openSet.getSize(), true)) {
                            if (maxTotalCost < 1000000000 || needNonPanicProcessing || fastPartialRecalc) {
                                throw new IllegalArgumentException("memory limit reached");
                            }
                            memoryPanicMode = true;
                            logInfo("************************ memory limit reached, enabled memory panic mode *************************");
                        }
                    }
                    if (memoryPanicMode) {
                        openBorderList.add(path);
                        continue;
                    }
                }
                needNonPanicProcessing = false;


                if (fastPartialRecalc && matchPath != null && path.cost > 30L * firstMatchCost && !costCuttingTrack.isDirty) {
                    logInfo("early exit: firstMatchCost=" + firstMatchCost + " path.cost=" + path.cost);

                    // use an early exit, unless there's a realistc chance to complete within the timeout
                    if (path.cost > maxTotalCost / 2 && System.currentTimeMillis() - startTime < maxRunningTime / 3) {
                        logInfo("early exit supressed, running for completion, resetting timeout");
                        startTime = System.currentTimeMillis();
                        fastPartialRecalc = false;
                    } else {
                        throw new IllegalArgumentException("early exit for a close recalc");
                    }
                }

                if (nodeLimit > 0 && --nodeLimit == 0) { // check node-limit for target island search
                    return null;
                }

                nodesVisited++;
                linksProcessed++;

                final OsmLink currentLink = path.getLink();
                final OsmNode sourceNode = path.getSourceNode();
                final OsmNode currentNode = path.getTargetNode();

                if (currentLink.isLinkUnused()) {
                    continue;
                }

                final long currentNodeId = currentNode.getIdFromPos();
                final long sourceNodeId = sourceNode.getIdFromPos();

                if (!path.didEnterDestinationArea()) {
                    islandNodePairs.addTempPair(sourceNodeId, currentNodeId);
                }

                if (path.treedepth != 1) {
                    if (path.treedepth == 0) { // hack: sameSegment Paths marked treedepth=0 to pass above check
                        path.treedepth = 1;
                    }

                    if ((sourceNodeId == endNodeId1 && currentNodeId == endNodeId2)
                            || (sourceNodeId == endNodeId2 && currentNodeId == endNodeId1)) {
                        // track found, compile
                        logInfo("found track at cost " + path.cost + " nodesVisited = " + nodesVisited);
                        final OsmTrack t = compileTrack(path);
                        t.showspeed = routingContext.showspeed;
                        t.showSpeedProfile = routingContext.showSpeedProfile;
                        return t;
                    }

                    // check for a match with the cost-cutting-track
                    if (costCuttingTrack != null) {
                        final OsmPathElement pe = costCuttingTrack.getLink(sourceNodeId, currentNodeId);
                        if (pe != null) {
                            // remember first match cost for fast termination of partial recalcs
                            int parentcost = path.originElement == null ? 0 : path.originElement.cost;

                            // hitting start-element of costCuttingTrack?
                            final int c = path.cost - parentcost - pe.cost;
                            if (c > 0) {
                                parentcost += c;
                            }

                            if (parentcost < firstMatchCost) {
                                firstMatchCost = parentcost;
                            }

                            final int costEstimate = path.cost
                                    + path.elevationCorrection()
                                    + (costCuttingTrack.cost - pe.cost);
                            if (costEstimate <= maxTotalCost) {
                                matchPath = OsmPathElement.create(path);
                            }
                            if (costEstimate < maxTotalCost) {
                                logInfo("maxcost " + maxTotalCost + " -> " + costEstimate);
                                maxTotalCost = costEstimate;
                            }
                        }
                    }
                }

                final OsmLinkHolder firstLinkHolder = currentLink.getFirstLinkHolder(sourceNode);
                for (OsmLinkHolder linkHolder = firstLinkHolder; linkHolder != null; linkHolder = linkHolder.getNextForLink()) {
                    ((OsmPath) linkHolder).airdistance = -1; // invalidate the entry in the open set;
                }

                if (path.treedepth > 1) {
                    final boolean isBidir = currentLink.isBidirectional();
                    sourceNode.unlinkLink(currentLink);

                    // if the counterlink is alive and does not yet have a path, remove it
                    if (isBidir && currentLink.getFirstLinkHolder(currentNode) == null && !routingContext.considerTurnRestrictions) {
                        currentNode.unlinkLink(currentLink);
                    }
                }

                // recheck cutoff before doing expensive stuff
                final int addDiff = 100;
                if (path.cost + path.airdistance > maxTotalCost + addDiff) {
                    continue;
                }

                nodesCache.nodesMap.currentMaxCost = maxTotalCost;
                nodesCache.nodesMap.currentPathCost = path.cost;
                nodesCache.nodesMap.destination = endPos;

                routingContext.firstPrePath = null;

                for (OsmLink link = currentNode.firstlink; link != null; link = link.getNext(currentNode)) {
                    final OsmNode nextNode = link.getTarget(currentNode);

                    if (!nodesCache.obtainNonHollowNode(nextNode)) {
                        continue; // border node?
                    }
                    if (nextNode.firstlink == null) {
                        continue; // don't care about dead ends
                    }
                    if (nextNode == sourceNode) {
                        continue; // border node?
                    }

                    final OsmPrePath prePath = routingContext.createPrePath(path, link);
                    if (prePath != null) {
                        prePath.next = routingContext.firstPrePath;
                        routingContext.firstPrePath = prePath;
                    }
                }

                for (OsmLink link = currentNode.firstlink; link != null; link = link.getNext(currentNode)) {
                    final OsmNode nextNode = link.getTarget(currentNode);

                    if (!nodesCache.obtainNonHollowNode(nextNode)) {
                        continue; // border node?
                    }
                    if (nextNode.firstlink == null) {
                        continue; // don't care about dead ends
                    }
                    if (nextNode == sourceNode) {
                        continue; // border node?
                    }

                    if (guideTrack != null) {
                        final int gidx = path.treedepth + 1;
                        if (gidx >= guideTrack.nodes.size()) {
                            continue;
                        }
                        final OsmPathElement guideNode = guideTrack.nodes.get(routingContext.inverseRouting ? guideTrack.nodes.size() - 1 - gidx : gidx);
                        final long nextId = nextNode.getIdFromPos();
                        if (nextId != guideNode.getIdFromPos()) {
                            // not along the guide-track, discard, but register for voice-hint processing
                            if (routingContext.turnInstructionMode > 0) {
                                final OsmPath detour = routingContext.createPath(path, link, refTrack, true);
                                if (detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2) {
                                    guideTrack.registerDetourForId(currentNode.getIdFromPos(), OsmPathElement.create(detour));
                                }
                            }
                            continue;
                        }
                    }

                    OsmPath bestPath = null;

                    boolean isFinalLink = false;
                    final long targetNodeId = nextNode.getIdFromPos();
                    if ((currentNodeId == endNodeId1 || currentNodeId == endNodeId2) && (targetNodeId == endNodeId1 || targetNodeId == endNodeId2)) {
                        isFinalLink = true;
                    }

                    for (OsmLinkHolder linkHolder = firstLinkHolder; linkHolder != null; linkHolder = linkHolder.getNextForLink()) {
                        final OsmPath otherPath = (OsmPath) linkHolder;
                        try {
                            if (isFinalLink) {
                                endPos.radius = 1.5; // 1.5 meters is the upper limit that will not change the unit-test result..
                                routingContext.setWaypoint(endPos, true);
                            }
                            final OsmPath testPath = routingContext.createPath(otherPath, link, refTrack, guideTrack != null);
                            if (testPath.cost >= 0 && (bestPath == null || testPath.cost < bestPath.cost) &&
                                    (testPath.sourceNode.getIdFromPos() != testPath.targetNode.getIdFromPos())) {
                                bestPath = testPath;
                            }
                        } finally {
                            if (isFinalLink) {
                                routingContext.unsetWaypoint();
                            }
                        }
                    }
                    if (bestPath != null) {
                        bestPath.airdistance = isFinalLink ? 0 : nextNode.calcDistance(endPos);

                        final boolean inRadius = boundary == null || boundary.isInBoundary(nextNode, bestPath.cost);

                        if (inRadius && (isFinalLink || bestPath.cost + bestPath.airdistance <= (lastAirDistanceCostFactor != 0. ? maxTotalCost * lastAirDistanceCostFactor : maxTotalCost) + addDiff)) {
                            // add only if this may beat an existing path for that link
                            OsmLinkHolder dominator = link.getFirstLinkHolder(currentNode);
                            while (dominator != null) {
                                final OsmPath dp = (OsmPath) dominator;
                                if (dp.airdistance != -1 && bestPath.definitlyWorseThan(dp)) {
                                    break;
                                }
                                dominator = dominator.getNextForLink();
                            }

                            if (dominator == null) {
                                bestPath.treedepth = path.treedepth + 1;
                                link.addLinkHolder(bestPath, currentNode);
                                addToOpenset(bestPath);
                            }
                        }
                    }
                }
            }
        }

        if (nodesVisited < MAXNODES_ISLAND_CHECK && islandNodePairs.getFreezeCount() < 5) {
            throw new RoutingIslandException();
        }

        return null;
    }
find the elevation type for position
to determine the filter value

@param n  the point
@return  the filter value for 1sec / 3sec elevation source
main/src/main/java/cgeo/geocaching/brouter/core/RoutingEngine.java