List<string> _tunnelLayerIDs; // tunnel layer IDs

        #endregion Fields

        #region Constructors

        public SimpleProfileAnalysisWindow()
        {
            InitializeComponent();

            _settings = new GeoProjSettings();
            SettingsHolder.DataContext = _settings;
            Loaded += SimpleProfileAnalysisWindow_Loaded;
            Unloaded += SimpleProfileAnalysisWindow_Unloaded;

            _mainFrame = Globals.mainframe;
            _prj = Globals.project;

            if (_mainFrame == null || _prj == null) { _initFailed = true; return; }

            _geologyDomain = _prj.getDomain(DomainType.Geology);
            _structureDomain = _prj.getDomain(DomainType.Structure);
            if (_geologyDomain == null || _structureDomain == null) { _initFailed = true; return; }

            // set the input view
            _inputView = _mainFrame.activeView;
            if (_inputView == null ||
                _inputView.eMap.MapType != EngineeringMapType.FootPrintMap)
                _inputView = _mainFrame.views.FirstOrDefault(
                    x => x.eMap.MapType == EngineeringMapType.FootPrintMap);
            if (_inputView == null) { _initFailed = true; return; }
            InputViewTB.DataContext = _inputView;

            _allBhs = _geologyDomain.getObjects("Borehole");
            _allSts = _geologyDomain.getObjects("Stratum");
            _bhLayerIDs = new List<string>();
            foreach (DGObjects objs in _allBhs)
                _bhLayerIDs.Add(objs.definition.GISLayerName);

            _allTunnels = _structureDomain.getObjects("Tunnel");
            _tunnelLayerIDs = new List<string>();
            foreach (DGObjects objs in _allTunnels)
                _tunnelLayerIDs.Add(objs.definition.GISLayerName);

            // add borehole layer as selectable layer
            _inputView.removeSelectableLayer("_ALL");
            _inputView.addSeletableLayer("0");     // "0" is the drawing layer ID
            foreach (string layerID in _bhLayerIDs)
                _inputView.addSeletableLayer(layerID);
            foreach (string layerID in _tunnelLayerIDs)
                _inputView.addSeletableLayer(layerID);

            // add a listener to object selection changed event
            _inputView.objSelectionChangedTrigger +=
                _inputView_objSelectionChangedListener;
            // add a listener to drawing graphics changed event
            _inputView.drawingGraphicsChangedTrigger +=
                _inputView_drawingGraphicsChangedListener;
        }
        public static ProjectBoreholeResult ProjectBoreholes(List<Tuple<Borehole, IMapPoint>> input,
            IPolyline projLine, GeoProjSettings geoProjSettings)
        {
            if (input == null || projLine == null)
                return null;

            // remove the boreholes that do not have geology infos,
            // so called 'empty' boreholes
            //
            input.RemoveAll(x =>
                x.Item1.Geologies == null || x.Item1.Geologies.Count == 0
                || x.Item1.Top == x.Item1.Base);

            // sort the boreholes according to their projected position on the projection line
            //
            List<ProjectedBorehole> sortedList = new List<ProjectedBorehole>();
            foreach (var tuple in input)
            {
                Borehole bh = tuple.Item1;
                IMapPoint p = tuple.Item2;

                double distance = 0;
                IMapPoint prjPnt = null;
                bool canProject = GeomUtil.ProjectPointToPolyline(p,
                    projLine.GetPoints(), ref distance, ref prjPnt);
                if (geoProjSettings.clipInProjectionLine == true && canProject == false)
                    continue;

                distance /= geoProjSettings.scale;
                distance += geoProjSettings.xOffset;
                ProjectedBorehole prjBorehole = new ProjectedBorehole();
                prjBorehole.Borehole = bh;
                prjBorehole.Distance = distance;
                prjBorehole.Pos = p;
                sortedList.Add(prjBorehole);
            }
            if (sortedList.Count == 0)
                return null;

            sortedList.Sort((x, y) => x.Distance.CompareTo(y.Distance));

            // extend borholes to same depth
            //
            if (geoProjSettings.extendBorehole)
            {
                ExtendBoreholes(input);
            }

            // perform the projection
            //
            ProjectBoreholeResult result = new ProjectBoreholeResult();

            List<STGraphic> stResults = new List<STGraphic>();
            ProjectedBorehole previousBh = null;
            foreach (ProjectedBorehole projectedBorehole in sortedList)
            {
                Borehole bh = projectedBorehole.Borehole;

                // draw strata
                if (geoProjSettings.drawStratum)
                {
                    if (previousBh == null)
                    {
                        previousBh = projectedBorehole;
                    }
                    else
                    {
                        List<STGraphic> stGraphics = LinkBorehole(
                            previousBh.Borehole, projectedBorehole.Borehole,
                            previousBh.Distance, projectedBorehole.Distance,
                            geoProjSettings.zScale);
                        previousBh = projectedBorehole;
                        stResults.AddRange(stGraphics);
                    }
                }

                // draw borehole
                if (geoProjSettings.drawBorehole)
                {
                    IGraphicCollection gc = ProjectBorehole(bh,
                        projectedBorehole.Distance, geoProjSettings.zScale);
                    result.bhGraphics[bh.id] = gc;
                }
            }

            // transfrom strata results
            foreach (STGraphic stGraphic in stResults)
            {
                int id = stGraphic.StratumID;
                if (result.stGraphics.ContainsKey(id))
                {
                    IGraphicCollection gc = result.stGraphics[id];
                    gc.Add(stGraphic.Graphic);
                }
                else
                {
                    IGraphicCollection gc = NewGraphicCollection();
                    gc.Add(stGraphic.Graphic);
                    result.stGraphics[id] = gc;
                }
            }

            // calculate extent
            IEnvelope ext = null;
            foreach (IGraphicCollection gc in result.bhGraphics.Values)
            {
                IEnvelope itemExt = GraphicsUtil.GetGraphicsEnvelope(gc);
                if (ext == null)
                    ext = itemExt;
                else
                    ext = ext.Union(itemExt);
            }
            result.Extent = ext;

            return result;
        }