         }
         
         fileprivate init(solid: Shape.Component) {
-            self.components = [solid]
-            self.cache = Cache()
-            self.boundary = self.components[0].boundary
-            self.area = abs(self.components[0].area)
+            self.init(components: [solid])
+        }
+        
+        fileprivate init<S : Sequence>(solid: Shape.Component, holes: S) where S.Element == Shape.Component {
+            self.init(components: [solid] + holes)
         }
     }
 }

            case .none: return (nil, false)
            }
        case let .regions(left, right): return (left.subtracting(right), false)
        case let .segments(loops): return (ShapeRegion(solids: loops.filter { self.area.sign == $0.solid.area.sign }.map { ShapeRegion.Solid(solid: $0.solid) }), false)
        }
    }
}

                    case .subset: return .overlap(.superset)
                    }
                case let .regions(lhs, rhs): return .regions(rhs, lhs)
                case let .segments(forward, backward): return self.area.sign == other.area.sign ? .segments(forward, backward) : .segments(backward, forward)
                }
            } else {
                let intersectTable = ConstructiveSolidResult.Table(self, other)
                if intersectTable.looping_left.count != 0 || intersectTable.looping_right.count != 0 {
                    constructiveSolidResultCache[other.cacheId] = .regions(ShapeRegion(solids: self.breakLoop(intersectTable.looping_left)), ShapeRegion(solids: other.breakLoop(intersectTable.looping_right)))
                } else {
                    
                    if intersectTable.graph.count == 0 {
                        constructiveSolidResultCache[other.cacheId] = .overlap(intersectTable.overlap)
                    } else {
                        let segments = createSegments(other, intersectTable.graph)
                        let forward = segments.filter { self.area.sign == $0.solid.area.sign }
                        let backward = segments.filter { self.area.sign != $0.solid.area.sign }
                        constructiveSolidResultCache[other.cacheId] = .segments(forward, backward)
                    }
                }
            }
