/// <summary>
        /// Retrieve the room plan view boundary
        /// polygon loops and convert to 2D integer-based.
        /// For optimisation and consistency reasons,
        /// convert all coordinates to integer values in
        /// millimetres. Revit precision is limited to
        /// 1/16 of an inch, which is abaut 1.2 mm, anyway.
        /// </summary>
        static JtLoops GetRoomLoops(Room room)
        {
            SpatialElementBoundaryOptions opt
                = new SpatialElementBoundaryOptions();

            opt.SpatialElementBoundaryLocation =
                SpatialElementBoundaryLocation.Center; // loops closed
            //SpatialElementBoundaryLocation.Finish; // loops not closed

            IList <IList <BoundarySegment> > loops = room.
                                                     GetBoundarySegments(opt);

            int nLoops = loops.Count;

            JtLoops jtloops = new JtLoops(nLoops);

            foreach (IList <BoundarySegment> loop in loops)
            {
                int nSegments = loop.Count;

                JtLoop jtloop = new JtLoop(nSegments);

                XYZ p0 = null; // loop start point
                XYZ p;         // segment start point
                XYZ q = null;  // segment end point

                foreach (BoundarySegment seg in loop)
                {
                    // Todo: handle non-linear curve.
                    // Especially: if two long lines have a
                    // short arc in between them, skip the arc
                    // and extend both lines.

                    p = seg.Curve.GetEndPoint(0);

                    jtloop.Add(new Point2dInt(p));

                    Debug.Assert(null == q || q.IsAlmostEqualTo(p),
                                 "expected last endpoint to equal current start point");

                    q = seg.Curve.GetEndPoint(1);

                    if (_debug_output)
                    {
                        Debug.Print("{0} --> {1}",
                                    Util.PointString(p),
                                    Util.PointString(q));
                    }
                    if (null == p0)
                    {
                        p0 = p; // save loop start point
                    }
                }
                Debug.Assert(q.IsAlmostEqualTo(p0),
                             "expected last endpoint to equal loop start point");

                jtloops.Add(jtloop);
            }
            return(jtloops);
        }
        /// <summary>
        /// Return polygon loops representing the size
        /// and location of given sheet and all the
        /// viewports it contains, regardless of type.
        /// </summary>
        static JtLoops GetSheetViewportLoops(
            SheetModelCollections modelCollections,
            ViewSheet sheet)
        {
            Document doc = sheet.Document;

            List <Viewport> viewports = sheet
                                        .GetAllViewports()
                                        .Select <ElementId, Viewport>(
                id => doc.GetElement(id) as Viewport)
                                        .ToList <Viewport>();

            int n = viewports.Count;

            modelCollections.ViewsInSheet[sheet.Id]
                = new List <ViewData>(n);

            JtLoops sheetViewportLoops = new JtLoops(n + 1);

            // sheet.get_BoundingBox( null ) returns (-100,-100),(100,100)

            BoundingBoxUV bb = sheet.Outline;                  // model coordinates (0,0), (2.76,1.95)

            JtBoundingBox2dInt ibb = new JtBoundingBox2dInt(); // millimeters (0,0),(840,...)

            ibb.ExpandToContain(new Point2dInt(bb.Min));
            ibb.ExpandToContain(new Point2dInt(bb.Max));

            JtLoop loop = new JtLoop(ibb.Corners);

            sheetViewportLoops.Add(loop);

            foreach (Viewport vp in viewports)
            {
                XYZ center = vp.GetBoxCenter(); // not used

                Outline outline = vp.GetBoxOutline();

                ibb.Init();

                ibb.ExpandToContain(
                    new Point2dInt(outline.MinimumPoint));

                ibb.ExpandToContain(
                    new Point2dInt(outline.MaximumPoint));

                loop = new JtLoop(ibb.Corners);

                sheetViewportLoops.Add(loop);

                ViewData d = new ViewData();
                d.Id = vp.ViewId;
                d.ViewportBoundingBox = loop.BoundingBox;

                modelCollections.ViewsInSheet[sheet.Id].Add(
                    d);
            }
            return(sheetViewportLoops);
        }
Beispiel #3
0
        /// <summary>
        /// Unite two collections of boundary
        /// loops into one single one.
        /// </summary>
        public static JtLoops operator+(JtLoops a, JtLoops b)
        {
            int     na  = a.Count;
            int     nb  = b.Count;
            JtLoops sum = new JtLoops(na + nb);

            sum.AddRange(a);
            sum.AddRange(b);
            return(sum);
        }
        /// <summary>
        /// List all the loops retrieved
        /// from the given element.
        /// </summary>
        static void ListLoops(Element e, JtLoops loops)
        {
            int nLoops = loops.Count;

            Debug.Print("{0} has {1}{2}",
                        Util.ElementDescription(e),
                        Util.PluralString(nLoops, "loop"),
                        Util.DotOrColon(nLoops));

            int i = 0;

            foreach (JtLoop loop in loops)
            {
                Debug.Print("  {0}: {1}", i++,
                            loop.ToString());
            }
        }
        /// <summary>
        /// Retrieve all plan view boundary loops from
        /// all solids of given element. This initial
        /// version passes each solid encountered in the
        /// given element to the ExtrusionAnalyzer one
        /// at a time, which obviously results in multiple
        /// loops, many of which are contained within the
        /// others. An updated version unites all the
        /// solids first and then uses the ExtrusionAnalyzer
        /// once only to obtain the true outside shadow
        /// contour.
        /// </summary>
        static JtLoops GetPlanViewBoundaryLoopsMultiple(
            Element e,
            ref int nFailures)
        {
            Autodesk.Revit.Creation.Application creapp
                = e.Document.Application.Create;

            JtLoops loops = new JtLoops(1);

            //int nSolids = 0;

            Options opt = new Options();

            GeometryElement geo = e.get_Geometry(opt);

            if (null != geo)
            {
                Document doc = e.Document;

                if (e is FamilyInstance)
                {
                    geo = geo.GetTransformed(
                        Transform.Identity);
                }

                //GeometryInstance inst = null;

                foreach (GeometryObject obj in geo)
                {
                    AddLoops(creapp, loops, obj, ref nFailures);

                    //inst = obj as GeometryInstance;
                }

                //if( 0 == nSolids && null != inst )
                //{
                //  geo = inst.GetSymbolGeometry();

                //  foreach( GeometryObject obj in geo )
                //  {
                //    AddLoops( creapp, loops, obj, ref nFailures );
                //  }
                //}
            }
            return(loops);
        }
        /// <summary>
        /// Add all plan view boundary loops from
        /// given solid to the list of loops.
        /// The creation application argument is used to
        /// reverse the extrusion analyser output curves
        /// in case they are badly oriented.
        /// </summary>
        /// <returns>Number of loops added</returns>
        static int AddLoops(
            Autodesk.Revit.Creation.Application creapp,
            JtLoops loops,
            GeometryObject obj,
            ref int nExtrusionAnalysisFailures)
        {
            int nAdded = 0;

            Solid solid = obj as Solid;

            if (null != solid &&
                0 < solid.Faces.Size)
            {
                //Plane plane = new Plane(XYZ.BasisX,
                //  XYZ.BasisY, XYZ.Zero); // 2016

                Plane plane = Plane.CreateByOriginAndBasis(
                    XYZ.Zero, XYZ.BasisX, XYZ.BasisY); // 2017

                ExtrusionAnalyzer extrusionAnalyzer = null;

                try
                {
                    extrusionAnalyzer = ExtrusionAnalyzer.Create(
                        solid, plane, XYZ.BasisZ);
                }
                catch (Autodesk.Revit.Exceptions
                       .InvalidOperationException)
                {
                    ++nExtrusionAnalysisFailures;
                    return(nAdded);
                }

                Face face = extrusionAnalyzer
                            .GetExtrusionBase();

                loops.Add(GetLoop(creapp, face));

                ++nAdded;
            }
            return(nAdded);
        }
        /// <summary>
        /// Upload the selected rooms and the furniture
        /// they contain to the cloud database.
        /// </summary>
        public static void UploadRoom(
            Document doc,
            Room room)
        {
            BoundingBoxXYZ bb = room.get_BoundingBox(null);

            if (null == bb)
            {
                Util.ErrorMsg(string.Format("Skipping room {0} "
                                            + "because it has no bounding box.",
                                            Util.ElementDescription(room)));

                return;
            }

            JtLoops roomLoops = GetRoomLoops(room);

            ListLoops(room, roomLoops);

            List <Element> furniture
                = GetFurniture(room);

            // Map symbol UniqueId to symbol loop

            Dictionary <string, JtLoop> furnitureLoops
                = new Dictionary <string, JtLoop>();

            // List of instances referring to symbols

            List <JtPlacement2dInt> furnitureInstances
                = new List <JtPlacement2dInt>(
                      furniture.Count);

            int nFailures;

            foreach (FamilyInstance f in furniture)
            {
                FamilySymbol s = f.Symbol;

                string uid = s.UniqueId;

                if (!furnitureLoops.ContainsKey(uid))
                {
                    nFailures = 0;

                    JtLoops loops = GetPlanViewBoundaryLoops(
                        f, ref nFailures);

                    if (0 < nFailures)
                    {
                        Debug.Print("{0}: {1}",
                                    Util.ElementDescription(f),
                                    Util.PluralString(nFailures,
                                                      "extrusion analyser failure"));
                    }
                    ListLoops(f, loops);

                    if (0 < loops.Count)
                    {
                        // Assume first loop is outer one

                        furnitureLoops.Add(uid, loops[0]);
                    }
                }
                furnitureInstances.Add(
                    new JtPlacement2dInt(f));
            }
            IWin32Window revit_window
                = new JtWindowHandle(
                      ComponentManager.ApplicationWindow);

            string caption = doc.Title
                             + " : " + doc.GetElement(room.LevelId).Name
                             + " : " + room.Name;

            Bitmap bmp = GeoSnoop.DisplayRoom(roomLoops,
                                              furnitureLoops, furnitureInstances);

            GeoSnoop.DisplayImageInForm(revit_window,
                                        caption, false, bmp);

            DbUpload.DbUploadRoom(room, furniture,
                                  roomLoops, furnitureLoops);
        }
        /// <summary>
        /// Retrieve all plan view boundary loops from
        /// all solids of given element united together.
        /// If the element is a family instance, transform
        /// its loops from the instance placement
        /// coordinate system back to the symbol
        /// definition one.
        /// If no geometry can be determined, use the
        /// bounding box instead.
        /// </summary>
        static JtLoops GetPlanViewBoundaryLoops(
            Element e,
            ref int nFailures)
        {
            Autodesk.Revit.Creation.Application creapp
                = e.Document.Application.Create;

            JtLoops loops = null;

            Options opt = new Options();

            GeometryElement geo = e.get_Geometry(opt);

            if (null != geo)
            {
                Document doc = e.Document;

                if (e is FamilyInstance)
                {
                    // Retrieve family instance geometry
                    // transformed back to symbol definition
                    // coordinate space by inverting the
                    // family instance placement transformation

                    LocationPoint lp = e.Location
                                       as LocationPoint;

                    Transform t = Transform.CreateTranslation(
                        -lp.Point);

                    Transform r = Transform.CreateRotationAtPoint(
                        XYZ.BasisZ, -lp.Rotation, lp.Point);

                    geo = geo.GetTransformed(t * r);
                }

                loops = GetPlanViewBoundaryLoopsGeo(
                    creapp, geo, ref nFailures);
            }
            if (null == loops || 0 == loops.Count)
            {
                Debug.Print(
                    "Unable to determine geometry for "
                    + Util.ElementDescription(e)
                    + "; using bounding box instead.");

                BoundingBoxXYZ bb;

                if (e is FamilyInstance)
                {
                    bb = (e as FamilyInstance).Symbol
                         .get_BoundingBox(null);
                }
                else
                {
                    bb = e.get_BoundingBox(null);
                }
                JtLoop loop = new JtLoop(4);
                loop.Add(new Point2dInt(bb.Min));
                loop.Add(new Point2dInt(bb.Max.X, bb.Min.Y));
                loop.Add(new Point2dInt(bb.Max));
                loop.Add(new Point2dInt(bb.Min.X, bb.Max.Y));
                loops.Add(loop);
            }
            return(loops);
        }
        /// <summary>
        /// Retrieve all plan view boundary loops from
        /// all solids of the given element geometry
        /// united together.
        /// </summary>
        internal static JtLoops GetPlanViewBoundaryLoopsGeo(
            Autodesk.Revit.Creation.Application creapp,
            GeometryElement geo,
            ref int nFailures)
        {
            Solid union = null;

            Plane plane = new Plane(XYZ.BasisX,
                                    XYZ.BasisY, XYZ.Zero);

            foreach (GeometryObject obj in geo)
            {
                Solid solid = obj as Solid;

                if (null != solid &&
                    0 < solid.Faces.Size)
                {
                    // Some solids, e.g. in the standard
                    // content 'Furniture Chair - Office'
                    // cause an extrusion analyser failure,
                    // so skip adding those.

                    try
                    {
                        ExtrusionAnalyzer extrusionAnalyzer
                            = ExtrusionAnalyzer.Create(
                                  solid, plane, XYZ.BasisZ);
                    }
                    catch (Autodesk.Revit.Exceptions
                           .InvalidOperationException)
                    {
                        solid = null;
                        ++nFailures;
                    }

                    if (null != solid)
                    {
                        if (null == union)
                        {
                            union = solid;
                        }
                        else
                        {
                            try
                            {
                                union = BooleanOperationsUtils
                                        .ExecuteBooleanOperation(union, solid,
                                                                 BooleanOperationsType.Union);
                            }
                            catch (Autodesk.Revit.Exceptions
                                   .InvalidOperationException)
                            {
                                ++nFailures;
                            }
                        }
                    }
                }
            }

            JtLoops loops = new JtLoops(1);

            AddLoops(creapp, loops, union, ref nFailures);

            return(loops);
        }
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            //IWin32Window revit_window
            //  = new JtWindowHandle(
            //    ComponentManager.ApplicationWindow ); // pre-2020

            IWin32Window revit_window
                = new JtWindowHandle(uiapp.MainWindowHandle); // 2020

            if (null == doc)
            {
                Util.ErrorMsg("Please run this command in a valid"
                              + " Revit project document.");
                return(Result.Failed);
            }

            // Interactive sheet selection.

            FrmSelectSheets form = new FrmSelectSheets(doc);

            if (DialogResult.OK == form.ShowDialog(
                    revit_window))
            {
                List <ViewSheet> sheets
                    = form.GetSelectedSheets();

                int n = sheets.Count;

                string caption = Util.PluralString(
                    n, "Sheet") + " Selected";

                string msg = string.Join(", ",
                                         sheets.Select <Element, string>(
                                             e => Util.SheetDescription(e))) + ".";

                // Determine all floor plan views displayed
                // in the selected sheets.

                Dictionary <View, int> views
                    = new Dictionary <View, int>(
                          new ElementEqualityComparer());

                int nFloorPlans = 0;

                foreach (ViewSheet sheet in sheets)
                {
                    foreach (View v in sheet.GetAllPlacedViews()
                             .Select <ElementId, View>(id =>
                                                       doc.GetElement(id) as View))
                    {
                        if (!views.ContainsKey(v))
                        {
                            if (IsFloorPlan(v))
                            {
                                ++nFloorPlans;
                            }
                            views.Add(v, 0);
                        }
                        ++views[v];
                    }
                }

                msg += (1 == n)
          ? "\nIt contains"
          : "\nThey contain";

                n = views.Count;

                msg += string.Format(
                    " {0} including {1}: ",
                    Util.PluralString(n, "view"),
                    Util.PluralString(nFloorPlans,
                                      "floor plan"));

                msg += string.Join(", ",
                                   views.Keys.Select <Element, string>(
                                       e => e.Name)) + ".";

                Util.InfoMsg2(caption, msg, false);

                // Determine all categories occurring
                // in the views displayed by the sheets.

                List <Category> categories
                    = new List <Category>(
                          new CategoryCollector(views.Keys).Keys);

                // Sort categories alphabetically by name
                // to display them in selection form.

                categories.Sort(
                    delegate(Category c1, Category c2)
                {
                    return(string.Compare(c1.Name, c2.Name));
                });

                // Interactive category selection.

                FrmSelectCategories form2
                    = new FrmSelectCategories(categories);

                if (DialogResult.OK == form2.ShowDialog(
                        revit_window))
                {
                    categories = form2.GetSelectedCategories();

                    n = categories.Count;

                    caption = Util.PluralString(n, "Category")
                              + " Selected";

                    msg = string.Join(", ",
                                      categories.Select <Category, string>(
                                          e => e.Name)) + ".";

                    Util.InfoMsg2(caption, msg, false);

                    // Convert category list to a dictionary for
                    // more effective repeated lookup.
                    //
                    //Dictionary<ElementId, Category> catLookup =
                    //  categories.ToDictionary<Category, ElementId>(
                    //    c => c.Id );
                    //
                    // No, much better: set up a reusable element
                    // filter for the categories of interest:

                    ElementFilter categoryFilter
                        = new LogicalOrFilter(categories
                                              .Select <Category, ElementCategoryFilter>(
                                                  c => new ElementCategoryFilter(c.Id))
                                              .ToList <ElementFilter>());

                    // Instantiate a container for all
                    // cloud data repository content.

                    SheetModelCollections modelCollections
                        = new SheetModelCollections(
                              DbUpload.GetProjectInfo(doc).Id);

                    foreach (ViewSheet sheet in sheets)
                    {
                        // Define preview form caption.

                        caption = "Sheet and Viewport Loops - "
                                  + Util.SheetDescription(sheet);

                        // This is currently not used for anything.

                        ListSheetAndViewTransforms(sheet);

                        // Determine the polygon loops representing
                        // the size and location of given sheet and
                        // the viewports it contains.

                        JtLoops sheetViewportLoops
                            = GetSheetViewportLoops(
                                  modelCollections, sheet);

                        // Determine graphics for family instances,
                        // their symbols and other BIM parts.

                        GetBimGraphics(modelCollections,
                                       sheet, categoryFilter);

                        // Display sheet and viewports with the
                        // geometry retrieved in a temporary GeoSnoop
                        // form generated on the fly for debugging
                        // purposes.

                        Bitmap bmp = GeoSnoop.DisplaySheet(
                            sheet.Id, sheetViewportLoops,
                            modelCollections);

                        GeoSnoop.DisplayImageInForm(
                            revit_window, caption, false, bmp);

                        // Upload data to the cloud database.

                        DbUpload.DbUploadSheet(sheet,
                                               sheetViewportLoops, modelCollections);
                    }
                    DbUpdater.SetLastSequence();
                }
            }
            return(Result.Succeeded);
        }
        /// <summary>
        /// Determine the visible elements belonging to the
        /// specified categories in the views displayed by
        /// the given sheet and return their graphics and
        /// instance placements.
        /// Ignore all but the first geometry loop retrieved.
        /// </summary>
        /// <param name="modelCollections">Data container</param>
        /// <param name="sheet">The view sheet</param>
        /// <param name="categoryFilter">The desired categories</param>
        static void GetBimGraphics(
            SheetModelCollections modelCollections,
            ViewSheet sheet,
            ElementFilter categoryFilter)
        {
            bool list_ignored_elements = false;

            Document doc = sheet.Document;

            Autodesk.Revit.Creation.Application creapp
                = doc.Application.Create;

            Options opt = new Options();

            // There is no need and no possibility to set
            // the detail level when retrieving view geometry.
            // An attempt to specify the detail level will
            // cause writing the opt.View property to throw
            // "DetailLevel is already set. When DetailLevel
            // is set view-specific geometry can't be
            // extracted."
            //
            //opt.DetailLevel = ViewDetailLevel.Coarse;

            Debug.Print(sheet.Name);

            foreach (ViewPlan v in sheet.GetAllPlacedViews()
                     .Select <ElementId, View>(id =>
                                               doc.GetElement(id) as View)
                     .OfType <ViewPlan>()
                     .Where <ViewPlan>(v => IsFloorPlan(v)))
            {
                Debug.Print("  " + v.Name);

                modelCollections.BimelsInViews.Add(
                    v.Id, new List <ObjData>());

                opt.View = v;

                JtBoundingBox2dInt bimelBb
                    = new JtBoundingBox2dInt();

                FilteredElementCollector els
                    = new FilteredElementCollector(doc, v.Id)
                      .WherePasses(categoryFilter);

                foreach (Element e in els)
                {
                    GeometryElement geo = e.get_Geometry(opt);

                    FamilyInstance f = e as FamilyInstance;

                    if (null != f)
                    {
                        LocationPoint lp = e.Location
                                           as LocationPoint;

                        // Simply ignore family instances that
                        // have no location point or no location at
                        // all, e.g. panel.
                        // No, we should not ignore them, but
                        // treat tham as non-transformable parts.

                        if (null == lp)
                        {
                            if (list_ignored_elements)
                            {
                                Debug.Print(string.Format(
                                                "    ...  {0} has no location",
                                                e.Name));
                            }
                            f = null;

                            geo = geo.GetTransformed(
                                Transform.Identity);
                        }
                        else
                        {
                            FamilySymbol s = f.Symbol;

                            if (modelCollections.Symbols.ContainsKey(s.Id))
                            {
                                if (list_ignored_elements)
                                {
                                    Debug.Print("    ... symbol already handled "
                                                + e.Name + " --> " + s.Name);
                                }

                                // Symbol already defined, just add instance

                                JtPlacement2dInt placement
                                    = new JtPlacement2dInt(f);

                                // Expand bounding box around all BIM
                                // elements, ignoring the size of the
                                // actual geometry, assuming is is small
                                // in comparison and the insertion point
                                // lies within it.

                                bimelBb.ExpandToContain(
                                    placement.Translation);

                                InstanceData d = new InstanceData();
                                d.Id        = f.Id;
                                d.Symbol    = f.Symbol.Id;
                                d.Placement = placement;

                                modelCollections.BimelsInViews[v.Id]
                                .Add(d);

                                continue;
                            }

                            // Retrieve family instance geometry
                            // transformed back to symbol definition
                            // coordinate space by inverting the
                            // family instance placement transformation

                            Transform t = Transform.CreateTranslation(
                                -lp.Point);

                            Transform r = Transform.CreateRotationAtPoint(
                                XYZ.BasisZ, -lp.Rotation, lp.Point);

                            geo = geo.GetTransformed(t * r);
                        }
                    }

                    int nEmptySolids    = 0;
                    int nNonEmptySolids = 0;
                    int nCurves         = 0;
                    int nOther          = 0;

                    foreach (GeometryObject obj in geo)
                    {
                        // This was true before calling GetTransformed.
                        //Debug.Assert( obj is Solid || obj is GeometryInstance, "expected only solids and instances" );

                        // This was true before calling GetTransformed.
                        //Debug.Assert( ( obj is GeometryInstance ) == ( e is FamilyInstance ), "expected all family instances to have geometry instance" );

                        Debug.Assert(obj is Solid || obj is Line || obj is Arc, "expected only solids, lines and arcs after calling GetTransformed on instances");

                        // Todo: handle arcs, e.g. tessellate

                        Debug.Assert(Visibility.Visible == obj.Visibility, "expected only visible geometry objects");

                        Debug.Assert(obj.IsElementGeometry, "expected only element geometry");
                        //bool isElementGeometry = obj.IsElementGeometry;

                        Solid solid = obj as Solid;

                        if (null != solid)
                        {
                            if (0 < solid.Edges.Size)
                            {
                                ++nNonEmptySolids;
                            }
                            else
                            {
                                ++nEmptySolids;
                            }
                        }
                        else if (obj is Curve)
                        {
                            ++nCurves;
                        }
                        else
                        {
                            ++nOther;
                        }
                    }

                    Debug.Print("    {0}: {1} non-emtpy solids, "
                                + "{2} empty, {3} curves, {4} other",
                                e.Name, nNonEmptySolids, nEmptySolids,
                                nCurves, nOther);

                    JtLoops loops = null;

                    if (1 == nNonEmptySolids &&
                        0 == nEmptySolids + nCurves + nOther)
                    {
                        int nFailures = 0;

                        loops = CmdUploadRooms
                                .GetPlanViewBoundaryLoopsGeo(
                            creapp, geo, ref nFailures);
                    }
                    else
                    {
                        double z     = double.MinValue;
                        bool   first = true;

                        foreach (GeometryObject obj in geo)
                        {
                            // Do we need the graphics style?
                            // It might give us horrible things like
                            // colours etc.

                            ElementId id = obj.GraphicsStyleId;

                            //Debug.Print( "      " + obj.GetType().Name );

                            Solid solid = obj as Solid;

                            if (null == solid)
                            {
                                #region Debug code to ensure horizontal co-planar curves
#if DEBUG
                                Debug.Assert(obj is Line || obj is Arc, "expected only lines and arcs here");

                                Curve c = obj as Curve;

                                if (first)
                                {
                                    z = c.GetEndPoint(0).Z;

                                    Debug.Assert(Util.IsEqual(z, c.GetEndPoint(1).Z),
                                                 "expected a plan view with all Z values equal");

                                    first = false;
                                }
                                else
                                {
                                    Debug.Assert(Util.IsEqual(z, c.GetEndPoint(0).Z),
                                                 "expected a plan view with all Z values equal");

                                    Debug.Assert(Util.IsEqual(z, c.GetEndPoint(1).Z),
                                                 "expected a plan view with all Z values equal");
                                }

                                Debug.Print("      {0} {1}",
                                            obj.GetType().Name,
                                            Util.CurveEndpointString(c));
#endif // DEBUG
                                #endregion // Debug code to ensure horizontal co-planar curves
                            }
                            else if (1 == solid.Faces.Size)
                            {
                                Debug.Print(
                                    "      solid with 1 face");

                                foreach (Face face in solid.Faces)
                                {
                                    #region Debug code to print out face edges
#if DEBUG
                                    foreach (EdgeArray loop in
                                             face.EdgeLoops)
                                    {
                                        foreach (Edge edge in loop)
                                        {
                                            // This returns the curves already
                                            // correctly oriented:

                                            Curve c = edge
                                                      .AsCurveFollowingFace(face);

                                            Debug.Print("        {0}: {1} {2}",
                                                        edge.GetType().Name,
                                                        c.GetType().Name,
                                                        Util.CurveEndpointString(c));
                                        }
                                    }
#endif // DEBUG
                                    #endregion // Debug code to print out face edges

                                    if (null == loops)
                                    {
                                        loops = new JtLoops(1);
                                    }
                                    loops.Add(CmdUploadRooms.GetLoop(
                                                  creapp, face));
                                }
                            }
                            else
                            {
                                #region Debug code for exceptional cases
#if DEBUG_2
                                Debug.Assert(1 >= solid.Faces.Size, "expected at most one visible face in plan view for my simple solids");

                                int n = solid.Edges.Size;

                                if (0 < n)
                                {
                                    Debug.Print(
                                        "      solid with {0} edges", n);

                                    Face[] face2 = new Face[] { null, null };
                                    Face   face  = null;

                                    foreach (Edge edge in solid.Edges)
                                    {
                                        if (null == face2[0])
                                        {
                                            face2[0] = edge.GetFace(0);
                                            face2[1] = edge.GetFace(1);
                                        }
                                        else if (null == face)
                                        {
                                            if (face2.Contains <Face>(edge.GetFace(0)))
                                            {
                                                face = edge.GetFace(0);
                                            }
                                            else if (face2.Contains <Face>(edge.GetFace(1)))
                                            {
                                                face = edge.GetFace(1);
                                            }
                                            else
                                            {
                                                Debug.Assert(false,
                                                             "expected all edges to belong to one face");
                                            }
                                        }
                                        else
                                        {
                                            Debug.Assert(face == edge.GetFace(0) ||
                                                         face == edge.GetFace(1),
                                                         "expected all edges to belong to one face");
                                        }

                                        Curve c = edge.AsCurve();

                                        // This returns the curves already
                                        // correctly oriented:

                                        //Curve curve = e.AsCurveFollowingFace(
                                        //  face );

                                        Debug.Print("        {0}: {1} {2}",
                                                    edge.GetType().Name,
                                                    c.GetType().Name,
                                                    Util.CurveEndpointString(c));
                                    }
                                }
#endif // DEBUG
                                #endregion // Debug code for exceptional cases
                            }
                        }
                    }

                    // Save the part or instance and
                    // the geometry retrieved for it.
                    // This is where we drop all geometry but
                    // the first loop.

                    if (null != loops)
                    {
                        GeomData gd = new GeomData();
                        gd.Loop = loops[0];

                        if (null == f)
                        {
                            // Add part with absolute geometry

                            gd.Id = e.Id;

                            modelCollections.BimelsInViews[v.Id].Add(
                                gd);

                            // Expand bounding box around all BIM
                            // elements.

                            bimelBb.ExpandToContain(
                                gd.Loop.BoundingBox);
                        }
                        else
                        {
                            // Define symbol and add instance

                            JtPlacement2dInt placement
                                = new JtPlacement2dInt(f);

                            InstanceData id = new InstanceData();
                            id.Id        = f.Id;
                            id.Symbol    = f.Symbol.Id;
                            id.Placement = placement;

                            modelCollections.BimelsInViews[v.Id].Add(
                                id);

                            gd.Id = f.Symbol.Id;

                            modelCollections.Symbols.Add(
                                f.Symbol.Id, gd);

                            // Expand bounding box around all BIM
                            // elements.

                            JtBoundingBox2dInt bb     = gd.Loop.BoundingBox;
                            Point2dInt         vtrans = placement.Translation;
                            bimelBb.ExpandToContain(bb.Min + vtrans);
                            bimelBb.ExpandToContain(bb.Max + vtrans);
                        }
                    }
                }

                // Set up BIM bounding box for this view

                modelCollections.ViewsInSheet[sheet.Id].Find(
                    v2 => v2.Id.IntegerValue.Equals(
                        v.Id.IntegerValue)).BimBoundingBox
                    = bimelBb;
            }
        }
Beispiel #12
0
        /// <summary>
        /// Display sheet, the views it contains, the BIM
        /// parts and  family instances they display in a
        /// temporary form generated on the fly.
        /// </summary>
        /// <param name="owner">Owner window</param>
        /// <param name="caption">Form caption</param>
        /// <param name="modal">Modal versus modeless</param>
        /// <param name="roomLoops">Sheet and viewport boundary loops</param>
        /// <param name="geometryLoopss">Family symbol and part geometry</param>
        /// <param name="familyInstances">Family instances</param>
        public static Bitmap DisplaySheet(
            ElementId sheetId,
            JtLoops sheetViewportLoops,
            SheetModelCollections modelCollections)
        {
            // Source rectangle.

            JtBoundingBox2dInt bbFrom = sheetViewportLoops
                                        .BoundingBox;

            // Adjust target rectangle height to the
            // displayee loop height.

            int width  = _form_width;
            int height = (int)(width * bbFrom.AspectRatio + 0.5);

            // Specify transformation target rectangle
            // including a margin.

            int top    = 0;
            int left   = 0;
            int bottom = height - (_margin + _margin);

            Point[] parallelogramPoints = new Point[] {
                new Point(left + _margin, bottom),         // upper left
                new Point(left + width - _margin, bottom), // upper right
                new Point(left + _margin, top + _margin)   // lower left
            };

            // Transform from native loop coordinate system
            // (sheet) to target display coordinates form).

            Matrix transformSheetBbToForm = new Matrix(
                bbFrom.Rectangle, parallelogramPoints);

            Bitmap   bmp      = new Bitmap(width, height);
            Graphics graphics = Graphics.FromImage(bmp);

            graphics.Clear(System.Drawing.Color.White);

            // Display sheet and viewport rectangles.

            DrawLoopsOnGraphics(graphics,
                                sheetViewportLoops.GetGraphicsPathLines(),
                                transformSheetBbToForm);

            // Iterate over the views and display the
            // elements for each one appropriately
            // scaled and translated to fit.

            List <ViewData> views = modelCollections
                                    .ViewsInSheet[sheetId];

            Dictionary <ElementId, GeomData> geometryLookup
                = modelCollections.Symbols;

            Matrix             transformBimToViewport;
            JtBoundingBox2dInt bbTo;
            JtLoop             loop;

            foreach (ViewData view in views)
            {
                ElementId vid = view.Id;

                if (!modelCollections.BimelsInViews
                    .ContainsKey(vid))
                {
                    // This is not a floor plan view, so
                    // we have nothing to display in it.

                    continue;
                }

                // Determine transform from model space in mm
                // to the viewport associated with this view.

                bbFrom = view.BimBoundingBox;
                bbTo   = view.ViewportBoundingBox;

                Debug.Print(view.ToString());

                // Adjust target rectangle height to the
                // displayee loop height.

                //height = (int) ( width * bbFrom.AspectRatio + 0.5 );

                // Specify transformation target rectangle
                // including a margin, and center the target
                // rectangle vertically.

                top    = bbTo.Min.Y + _margin2;
                left   = bbTo.Min.X + _margin2;
                bottom = bbTo.Max.Y - _margin2;
                width  = bbTo.Width - (_margin2 + _margin2);

                parallelogramPoints = new Point[] {
                    new Point(left, top),         // upper left
                    new Point(left + width, top), // upper right
                    new Point(left, bottom)       // lower left
                };

                // Transform from native loop coordinate system
                // (sheet) to target display coordinates form).

                transformBimToViewport = new Matrix(
                    bbFrom.Rectangle, parallelogramPoints);

                // Retrieve the list of BIM elements
                // displayed in this view.

                List <ObjData> bimels = modelCollections
                                        .BimelsInViews[vid];

                List <Point[]> loops = new List <Point[]>(1);
                loops.Add(new Point[] { });

                Matrix placement = new Matrix();

                foreach (ObjData bimel in bimels)
                {
                    placement.Reset();

                    InstanceData inst = bimel as InstanceData;

                    if (null != inst)
                    {
                        loop = geometryLookup[inst.Symbol].Loop;
                        Point2dInt v = inst.Placement.Translation;
                        placement.Rotate(inst.Placement.Rotation);
                        placement.Translate(v.X, v.Y, MatrixOrder.Append);
                    }
                    else
                    {
                        Debug.Assert(bimel is GeomData, "expected part with geometry");

                        loop = ((GeomData)bimel).Loop;
                    }
                    loops[0] = loop.GetGraphicsPathLines();

                    placement.Multiply(transformBimToViewport, MatrixOrder.Append);
                    placement.Multiply(transformSheetBbToForm, MatrixOrder.Append);

                    DrawLoopsOnGraphics(graphics, loops, placement);
                }
            }
            return(bmp);
        }
Beispiel #13
0
        /// <summary>
        /// Display room and furniture in a temporary form
        /// generated on the fly.
        /// </summary>
        /// <param name="roomLoops">Room boundary loops</param>
        /// <param name="geometryLoops">Family symbol geometry</param>
        /// <param name="familyInstances">Family instances</param>
        public static Bitmap DisplayRoom(
            JtLoops roomLoops,
            Dictionary <string, JtLoop> geometryLoops,
            List <JtPlacement2dInt> familyInstances)
        {
            JtBoundingBox2dInt bbFrom = roomLoops.BoundingBox;

            // Adjust target rectangle height to the
            // displayee loop height.

            int width  = _form_width;
            int height = (int)(width * bbFrom.AspectRatio + 0.5);

            //SizeF fsize = new SizeF( width, height );

            //SizeF scaling = new SizeF( 1, 1 );
            //PointF translation = new PointF( 0, 0 );

            //GetTransform( fsize, bbFrom,
            //  ref scaling, ref translation, true );

            //Matrix transform1 = new Matrix(
            //  new Rectangle(0,0,width,height),
            //  bbFrom.GetParallelogramPoints());
            //transform1.Invert();

            // the bounding box fills the rectangle
            // perfectly and completely, inverted and
            // non-uniformly distorted:

            //Point2dInt pmin = bbFrom.Min;
            //Rectangle rect = new Rectangle(
            //  pmin.X, pmin.Y, bbFrom.Width, bbFrom.Height );
            //Point[] parallelogramPoints = new Point [] {
            //  new Point( 0, 0 ), // upper left
            //  new Point( width, 0 ), // upper right
            //  new Point( 0, height ) // lower left
            //};

            // the bounding box fills the rectangle
            // perfectly and completely, inverted and
            // non-uniformly distorted:

            // Specify transformation target rectangle
            // including a margin.

            int bottom = height - (_margin + _margin);

            Point[] parallelogramPoints = new Point[] {
                new Point(_margin, bottom),         // upper left
                new Point(width - _margin, bottom), // upper right
                new Point(_margin, _margin)         // lower left
            };

            // Transform from native loop coordinate system
            // to target display coordinates.

            Matrix transform = new Matrix(
                bbFrom.Rectangle, parallelogramPoints);

            Bitmap   bmp      = new Bitmap(width, height);
            Graphics graphics = Graphics.FromImage(bmp);

            graphics.Clear(System.Drawing.Color.White);

            DrawLoopsOnGraphics(graphics,
                                roomLoops.GetGraphicsPathLines(), transform);

            if (null != familyInstances)
            {
                List <Point[]> loops = new List <Point[]>(1);
                loops.Add(new Point[] { });

                foreach (JtPlacement2dInt i in familyInstances)
                {
                    Point2dInt v         = i.Translation;
                    Matrix     placement = new Matrix();
                    placement.Rotate(i.Rotation);
                    placement.Translate(v.X, v.Y, MatrixOrder.Append);
                    placement.Multiply(transform, MatrixOrder.Append);
                    loops[0] = geometryLoops[i.SymbolId]
                               .GetGraphicsPathLines();

                    DrawLoopsOnGraphics(graphics, loops, placement);
                }
            }
            return(bmp);
        }
Beispiel #14
0
        /// <summary>
        /// Upload model, level, room and furniture data
        /// to an IrisCouch hosted CouchDB data repository.
        /// </summary>
        static public void DbUploadRoom(
            Room room,
            List <Element> furniture,
            JtLoops roomLoops,
            Dictionary <string, JtLoop> furnitureLoops)
        {
            CouchDatabase db = new RoomEditorDb().Db;

            Document doc = room.Document;

            Element projectInfo = GetProjectInfo(doc);

            DbModel dbModel = GetDbModel(db, projectInfo);

            Element level = doc.GetElement(room.LevelId);

            string uid = level.UniqueId;

            DbLevel dbLevel;

            if (db.DocumentExists(uid))
            {
                dbLevel = db.GetDocument <DbLevel>(uid);

                Debug.Assert(
                    dbLevel.Id.Equals(level.UniqueId),
                    "expected equal ids");

                dbLevel.Description = Util.ElementDescription(
                    level);

                dbLevel.Name    = level.Name;
                dbLevel.ModelId = projectInfo.UniqueId;

                dbLevel = db.UpdateDocument <DbLevel>(
                    dbLevel);
            }
            else
            {
                dbLevel = new DbLevel(uid);

                dbLevel.Description = Util.ElementDescription(
                    level);

                dbLevel.Name    = level.Name;
                dbLevel.ModelId = projectInfo.UniqueId;

                dbLevel = db.CreateDocument <DbLevel>(
                    dbLevel);
            }

            uid = room.UniqueId;

            DbRoom dbRoom;

            if (db.DocumentExists(uid))
            {
                dbRoom = db.GetDocument <DbRoom>(uid);

                Debug.Assert(
                    dbRoom.Id.Equals(room.UniqueId),
                    "expected equal ids");

                dbRoom.Description = Util.ElementDescription(
                    room);

                dbRoom.Name    = room.Name;
                dbRoom.LevelId = level.UniqueId;
                dbRoom.Loops   = roomLoops.SvgPath;
                dbRoom.ViewBox = roomLoops.BoundingBox.SvgViewBox;

                dbRoom = db.UpdateDocument <DbRoom>(dbRoom);
            }
            else
            {
                dbRoom = new DbRoom(uid);

                dbRoom.Description = Util.ElementDescription(
                    room);

                dbRoom.Name    = room.Name;
                dbRoom.LevelId = level.UniqueId;
                dbRoom.Loops   = roomLoops.SvgPath;
                dbRoom.ViewBox = roomLoops.BoundingBox.SvgViewBox;

                dbRoom = db.CreateDocument <DbRoom>(dbRoom);
            }

            foreach (KeyValuePair <string, JtLoop> p in furnitureLoops)
            {
                uid = p.Key;
                Element e = doc.GetElement(uid);
                if (db.DocumentExists(uid))
                {
                    DbSymbol symbol = db.GetDocument <DbSymbol>(
                        uid);

                    symbol.Description = Util.ElementDescription(e);
                    symbol.Name        = e.Name;
                    symbol.Loop        = p.Value.SvgPath;

                    symbol = db.UpdateDocument <DbSymbol>(symbol);
                }
                else
                {
                    DbSymbol symbol = new DbSymbol(uid);

                    symbol.Description = Util.ElementDescription(e);
                    symbol.Name        = e.Name;
                    symbol.Loop        = p.Value.SvgPath;

                    symbol = db.CreateDocument <DbSymbol>(symbol);
                }
            }

            foreach (FamilyInstance f in furniture)
            {
                uid = f.UniqueId;
                if (db.DocumentExists(uid))
                {
                    DbFurniture dbf = db.GetDocument <DbFurniture>(
                        uid);

                    dbf.Description = Util.ElementDescription(f);
                    dbf.Name        = f.Name;
                    dbf.RoomId      = room.UniqueId;
                    dbf.Properties  = Util.GetElementProperties(f);
                    dbf.SymbolId    = f.Symbol.UniqueId;
                    dbf.Transform   = new JtPlacement2dInt(f)
                                      .SvgTransform;

                    dbf = db.UpdateDocument <DbFurniture>(dbf);
                }
                else
                {
                    DbFurniture dbf = new DbFurniture(uid);

                    dbf.Description = Util.ElementDescription(f);
                    dbf.Name        = f.Name;
                    dbf.RoomId      = room.UniqueId;
                    dbf.Properties  = Util.GetElementProperties(f);
                    dbf.SymbolId    = f.Symbol.UniqueId;
                    dbf.Transform   = new JtPlacement2dInt(f)
                                      .SvgTransform;

                    dbf = db.CreateDocument <DbFurniture>(dbf);
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// Upload model, sheet, views it contains and
        /// their BIM elements to a CouchDB data repository.
        /// </summary>
        static public void DbUploadSheet(
            ViewSheet sheet,
            JtLoops sheetViewportLoops,
            SheetModelCollections modelCollections)
        {
            bool pre_existing = false;

            RoomEditorDb  rdb = new RoomEditorDb();
            CouchDatabase db  = rdb.Db;

            // Sheet

            Document doc = sheet.Document;

            Element e = GetProjectInfo(doc);

            DbModel dbModel = GetDbModel(db, e);

            DbSheet dbSheet = rdb.GetOrCreate <DbSheet>(
                ref pre_existing, sheet.UniqueId);

            dbSheet.Description = Util.SheetDescription(sheet);
            dbSheet.Name        = sheet.Name;
            dbSheet.ModelId     = e.UniqueId;
            dbSheet.Width       = sheetViewportLoops[0].BoundingBox.Width;
            dbSheet.Height      = sheetViewportLoops[0].BoundingBox.Height;

            dbSheet = pre_existing
        ? db.UpdateDocument <DbSheet>(dbSheet)
        : db.CreateDocument <DbSheet>(dbSheet);

            // Symbols

            Dictionary <ElementId, GeomData> geometryLookup
                = modelCollections.Symbols;

            foreach (KeyValuePair <ElementId, GeomData> p
                     in geometryLookup)
            {
                ElementId id = p.Key;

                e = doc.GetElement(id);

                DbSymbol symbol = rdb.GetOrCreate <DbSymbol>(
                    ref pre_existing, e.UniqueId);

                symbol.Description = Util.ElementDescription(e);
                symbol.Name        = e.Name;
                symbol.Loop        = p.Value.Loop.SvgPath;

                symbol = pre_existing
          ? db.UpdateDocument <DbSymbol>(symbol)
          : db.CreateDocument <DbSymbol>(symbol);
            }

            // Views and BIM elements

            List <ViewData> views = modelCollections
                                    .ViewsInSheet[sheet.Id];

            View               view;
            DbView             dbView;
            DbBimel            dbBimel;
            DbInstance         dbInstance = null;
            DbPart             dbPart     = null;
            JtBoundingBox2dInt bbFrom;
            JtBoundingBox2dInt bbTo;

            foreach (ViewData viewData in views)
            {
                ElementId vid = viewData.Id;

                if (!modelCollections.BimelsInViews
                    .ContainsKey(vid))
                {
                    // This is not a floor plan view, so
                    // we have nothing to display in it.

                    continue;
                }

                view = doc.GetElement(vid) as View;

                dbView = rdb.GetOrCreate <DbView>(
                    ref pre_existing, view.UniqueId);

                dbView.Description = Util.ElementDescription(view);
                dbView.Name        = view.Name;
                dbView.SheetId     = dbSheet.Id;

                bbFrom = viewData.BimBoundingBox;
                bbTo   = viewData.ViewportBoundingBox;

                dbView.X      = bbTo.Min.X;
                dbView.Y      = bbTo.Min.Y;
                dbView.Width  = bbTo.Width;
                dbView.Height = bbTo.Height;

                dbView.BimX      = bbFrom.Min.X;
                dbView.BimY      = bbFrom.Min.Y;
                dbView.BimWidth  = bbFrom.Width;
                dbView.BimHeight = bbFrom.Height;

                dbView = pre_existing
          ? db.UpdateDocument <DbView>(dbView)
          : db.CreateDocument <DbView>(dbView);

                // Retrieve the list of BIM elements
                // displayed in this view.

                List <ObjData> bimels = modelCollections
                                        .BimelsInViews[vid];

                foreach (ObjData bimel in bimels)
                {
                    e = doc.GetElement(bimel.Id);

                    InstanceData inst = bimel as InstanceData;

                    if (null != inst)
                    {
                        dbInstance = rdb.GetOrCreate <DbInstance>(
                            ref pre_existing, e.UniqueId);

                        dbInstance.SymbolId = doc.GetElement(
                            inst.Symbol).UniqueId;

                        dbInstance.Transform = inst.Placement
                                               .SvgTransform;

                        dbBimel = dbInstance;
                    }
                    else
                    {
                        Debug.Assert(bimel is GeomData,
                                     "expected part with geometry");

                        dbPart = rdb.GetOrCreate <DbPart>(
                            ref pre_existing, e.UniqueId);

                        dbPart.Loop = ((GeomData)bimel).Loop
                                      .SvgPath;

                        dbBimel = dbPart;
                    }
                    dbBimel.Description = Util.ElementDescription(e);
                    dbBimel.Name        = e.Name;
                    JtUidSet uids = new JtUidSet(dbBimel.ViewIds);
                    uids.Add(view.UniqueId);
                    dbBimel.ViewIds    = uids.Uids;
                    dbBimel.Properties = Util.GetElementProperties(e);

                    if (null != inst)
                    {
                        dbInstance = pre_existing
              ? db.UpdateDocument <DbInstance>(dbInstance)
              : db.CreateDocument <DbInstance>(dbInstance);
                    }
                    else
                    {
                        dbPart = pre_existing
              ? db.UpdateDocument <DbPart>(dbPart)
              : db.CreateDocument <DbPart>(dbPart);
                    }
                }
            }
        }