nicky-nym / city3d

3D architectural building models made using the three.js Javascript API
The Unlicense
9 stars 4 forks source link

Roof: add support for calculating gables, ridges, hips, valleys, and faces #18

Open nicky-nym opened 4 years ago

nicky-nym commented 4 years ago

Write code in Roof so that it can pass the tests in roof_tests.js. This means having Roof be smart enough to read an arbitrary JSON roof-spec and then deduce the correct geometry to satisfy the spec.

Once Roof supports these features, then convert House, Cottage, and Garage to use the new Roof code.

nicky-nym commented 4 years ago

Both Garage and Cottage should have pitched roofs, each with two end-gables as well as a smaller front gable. Garage and Cottage both extend Building. Garage and Cottage are each defined by a simple 10-line JSON spec, which is great, but in those JSON specs, the "roof:" property just calls for a flat roof with a short parapet.

Here's what the Garage spec looks like now, for the walls and roof:

  shape: { type: 'rectangle', data: xy(24, 21) },
  roof: { parapetHeight: UNIT.feet(1) }

Here's a proposal for the Garage spec with a gabled roof:

  shape: { type: 'rectangle', data: xy(24, 21) }, // garage footprint
  roof: {
    pitched: UNIT.degrees(30), // the slope of the roof
    eaves: UNIT.feet(1) // how far the roof extends past the wall
  },
  walls: [{
      type: 'gabled'   // left wall
    }, {
      type: 'pitched'  // rear wall
    }, {
      type: 'gabled',  // right wall, with person-sized door
      doors: [{ type: 'rectangle', data: xy(3, 7.5), at: xy(9, 0) }]
    }, {
      type: 'mixed',   // front wall, with garage door
      data: [{
        type: 'pitched',
        distance: UNIT.feet(1.5) // length of gutter to right of door
      }, {
        type: 'gabled',
        distance UNIT.feet(24 + 1 + 1 - 1.5 - 1.5), // span of gable
      }, {
        type: 'pitched',
        distance: UNIT.feet(1.5) // length of gutter to left of door
      }],
      doors: [{ type: 'rectangle', data: xy(16, 7.5), at: xy(4, 0) }]
    }
  ]

Assuming Garage had a spec with syntax that looked something like the example above, then it would be great if Garage could just extend Building, with no other hand-written code in Garage. Building would have all the code to create an instance of Roof, and four instances of Wall. And the the code in Roof and Wall would know how to create the correct Geometry objects.

The rear wall is just a simple rectangle, so that one is easy. The left and right walls are gabled, so they a pentagon-shaped (a rectangle with a triangle on top). The front wall is harder; it has 7 vertices and 7 edges on the outside, as well as an square opening for the garage door.

The Roof geometry is four flat surfaces. The rear face is a simple rectangle, set at angle (like a ramp). The front face is the same size as the rear, but it has a triangle cut out of it for the dormer, so it ends up with 7 vertices and 7 edges. And then there are two triangular faces for the symmetrical roof surfaces on either side of the dormer gable above the garage door.

So, four roof surfaces, which I think can be defined by a set of 10 points. The 10 points are:

I think all of the roof geometry and wall geometry can be derived from the JSON spec. The code would not be simple, but it would be deterministic. Once that code was working we could use it for a large variety of rooflines, including the existing Garage, Cottage, House, and MidriseComplex buildings, as well as lots of future buildings. I'm particularly eager to replace the 100+ lines of current roof code in House (lines 143 to 248), where all the vertices have been calculated and entered by hand.

nicky-nym commented 4 years ago

Web search results for the term "straight skeleton" include lots of papers and github repositories with code samples that might be useful...