土方工程-边坡土方量计算程序设计

本文最后更新于:7 个月前

程序更新: V1.1

  1. 新增加了功能:计算方格点内所有的开挖和填充的土方量
  2. 计算精度降低,在所有计算过程中对计算结果保留 3 位小数

问题

在土木工程施工的土方问题当中,边坡土方计算是一个重点和难点.何为边坡土方计算?如图所示

土方边坡

土方计算主要是土地平整的计算,其包括平整时的土方挖填和平整后的边坡修建.

在土地平整之后需要根据平面周围地形进行放坡处理.放坡处理时会涉及到边坡的挖填问题,因此需要根据施工高度和周围地形计算边坡土方的施工量.

假设

由于边坡放坡的坡脚线与平面高度以及周围地形的高程有关,现有的条件只能通过格点的高程来确定相应的施工高度,无法对平面周围的其他位置高程进行有效测量,同时,由于原地形地貌不可能保持沿单方向线性变化,因此根据有限条件简化模型:

  1. 假设格子内的施工高度都沿线性变化
  2. 格点外的周边地形高程与格点高程相同
  3. 相邻格点连线,及其外侧地形高程按照格点坡降均匀变化

基于这三个假设可以忽略不规则的地形地貌的影响,同时一定程度上对放坡地形进行了预测.

原理

土方工程先要进行土地平整,在网格内土地平整的施工量有相应的计算公式.土地平整完后为保证边坡稳定需要对边坡进行放坡,因此边坡也存在挖填问题.

边坡挖填土方平面示意图如图所示:

土方边坡[2]

示例格点的计算模型如下图所示:

土方边坡[2]

由图可得,挖填边坡宽度由施工高度决定,关于施工高度的计算可我的其他文章:土木工程施工-导论[1]

得到施工高度后,已知坡的宽高比$m$,相邻格点的间距$a$可以将计算边坡的施工高度问题转化成求解大量几何体形状体积的问题。

土地平整施工量计算

所有角点的符号都相同

当四个角点的符号都相同时,可直接把根据施工高度计算:$V = \frac{{{a^2}}}{4}({h_1} + {h_2} + {h_3} + {h_4})$ #### 角点有正有负 假定角点之间的连线都为直线,其体积公式为:${V_w} = \frac{{{a^2}}}{4}\frac{{\sum {|{h_w}|} }}{{\sum {|{h_i}|} }}$

角点

其中四个方格顶点的体积问题计算可简化成计算底边为正方形四棱锥体积问题,其中底边变长等于$m{h_{ij} }$,其中 m 为施工放坡的宽高比,${h_{ij} }$为计算格点的施工高度。

因此角点开挖体积的计算公式为:$V = {(m{h_{ij}})^2}*{h_{ij}}*\frac{1}{3}$ 其符号与施工高度同号

一端格点在零线上

一端格点在零线上即有一个格点的施工高度为 0,即可将该段的边坡工程计算简化成计算底面高度为另一侧施工高度,底面宽度为放坡底宽,高为相邻格点边长的三棱锥计算。

因此该类边的体积计算公式为:$V = mh_{ij}^2*\frac{1}{2}*a*\frac{1}{3}*\frac{{|{h_{ij} }|} }{{{h_{ij} }} }$ 其中$\frac{{|{h_{ij} }|} }{{{h_{ij} }} }$的作用是保证计算出的体积符号与施工高度符号一致

两个格点的值均不为零

此处有两种情况,第一种是两个格点同号,另一种异号

关于同号格点

同号格点可以直接按照三棱台计算,一侧底面面积${F_1} = \frac{1}{2}*mh_1^2$,另一侧底面面积${F_2} = \frac{1}{2}*mh_2^2$,则其中间截面面积为:${F_0} = \frac{{{F_1} + {F_2} }}{2}$ 可得棱台的体积计算公式: $$ \begin{array}{l} V = \frac{a}{6}({F_1} + {F_2} + 4{F_0})\\ = a{F_0} \end{array} $$

关于异号格点

零点其在中间,其施工高度既有开挖部分也有填充部分,因此需要分别计算,,首先按照线性插值法,找到零点位置:${a_1} = \frac{{a{h_1} }}{{|{h_1}| + |{h_2}|} }$ 对应的格点的施工体积为: $V = mh_1^2*\frac{1}{2}*{a_1}*\frac{1}{3}$

计算简要示意图如图所示:

土方边坡[2]

设计思路

  1. 先对相关参数进行读取:坡的宽高比 m,相邻格点间距 a,方格点的行数 raw,方格点的列数 col。
  2. 每四个格点单独提取出来
  3. 设计方格内的计算程序
  4. 先计算方格内的土方工程量
  5. 对行数和列数生成表格,读取各格点的施工高度
  6. 提取四个角点的施工高度分别计算
  7. 提取四边
  8. 设计计算每条边的施工体积
  9. 设计开挖填充工程量的数据结构模型 work

源程序

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <style>
    .deter {
      width: 50px;
      height: 50px;
    }
  </style>
  <title>计算挖方量</title>
</head>

<body>
  <div id="head">
    <pre>每行有多少角点?</pre>
    <input type="number" id="colCount" />
    <pre>有多少行?</pre>
    <input type="number" id="rowCount" />
    <pre> 坡的宽高比:</pre>
    <input type="number" id="M" />
    <pre> 方格边长a:</pre>
    <input type="number" id="A" />
    <button id="start">生成</button>
  </div>
  <script type="text/javascript">
    var start = document.getElementById("start");
    var m = "";
    var a = "";
    var d = null;
    start.addEventListener("click", res => {
      //document.removeChild(document.getElementById('forms'));

      var row = document.getElementById("rowCount").value;
      var col = document.getElementById("colCount").value;
      m = parseFloat(document.getElementById("M").value);
      a = parseFloat(document.getElementById("A").value);
      if (row == "" || col == "" || m == "" || a == "") return false;
      else createtables(row, col);
    });
    function createtables(row, col) {
      //搭建界面
      var determinants = new Array(row);
      for (var i = 0; i < row; i++) determinants[i] = new Array(col);
      var form = document.createElement("table");
      form.setAttribute("id", "forms");
      document.body.appendChild(form);
      var tr = new Array(row);
      for (var i = 0; i < row; i++) {
        tr[i] = document.createElement("tr");
        form.appendChild(tr[i]);
        for (var j = 0; j < col; j++) {
          var td = document.createElement("td");
          tr[i].appendChild(td);
          determinants[i][j] = document.createElement("input");
          determinants[i][j].setAttribute("class", "deter");
          determinants[i][j].setAttribute("type", "number");
          td.appendChild(determinants[i][j]);
        }
      }
      d = determinants;

      var count = document.createElement("button");
      count.setAttribute("id", "count");
      form.appendChild(count);

      count.appendChild(document.createTextNode("计算"));
      var result = document.createElement("div");
      result.setAttribute("id", "result");
      document.body.appendChild(result);
      count.onclick = function () {
        calculation(row, col, result);
      };
    }
    function calculation(row, col, result) {
      //总算法
      //安全检查
      d.forEach(item => {
        if (item.value == "") return false;
      });
      var total = new work();
      total.init(0, 0);

      //记录四个角点位置
      var corners = new Array(
        d[0][0].value,
        d[0][col - 1].value,
        d[row - 1][0].value,
        d[row - 1][col - 1].value
      );

      //提取四条边
      var up = new Array(),
        left = new Array(),
        buttom = new Array(),
        right = new Array();

      for (var i = 0; i < row; i++) {
        for (var j = 0; j < col; j++) {
          if (i == 0) up.push(parseFloat(d[i][j].value));
          if (j == 0) left.push(parseFloat(d[i][j].value));
          if (i == row - 1) buttom.push(parseFloat(d[i][j].value));
          if (j == col - 1) right.push(parseFloat(d[i][j].value));
        }
      }

      var sides = new Array(up, buttom, left, right);

      //提取格点
      var latticeResult = new work().init(0, 0);

      for (var i = 0; i < row - 1; i++) {
        for (var j = 0; j < col - 1; j++) {
          var temp = new Array(
            d[i][j].value,
            d[i + 1][j].value,
            d[i][j + 1].value,
            d[i + 1][j + 1].value
          );
          latticeResult.add(CalInGrid(temp));
          console.log(latticeResult.toString("格点"));
        }
      }

      //计算四个角点
      corners.forEach(h => {
        console.log(total.toString("角点"));
        total.add(CalCorner(parseFloat(h)));
      });
      //计算四条边
      sides.forEach(side => {
        console.log(total.toString("边坡"));
        total.add(CalSide(side));
      });

      console.log(total.toString("整个边坡"));
      //输出结果
      result.innerHTML =
        latticeResult.toString("格子") +
        "<br /> " +
        total.toString("整个边坡");
    }
    //计算一条边上的土方量
    function CalSide(side) {
      var total = new work();
      total.init(0, 0);
      var len = side.length;
      for (var i = 0; i < len - 1; i++) {
        temp = CalLattice(side[i], side[i + 1]);
        total.add(temp);
      }
      return total;
    }
    //计算相邻格点的挖填土方量
    function CalLattice(p1, p2) {
      if (p1 == 0 && p2 == 0) {
        return new work();
      }
      if (checkSign(p1, p2)) {
        //如果角点同号
        var V;
        if (p1 * p2 == 0) {
          //有一个是0格点,按照三角锥计算
          var h = checkZero(p1, p2);
          var sign = Math.abs(h) / h; //保存符号
          V = (a / 6) * h * h * m * sign;
        } else {
          //按照三棱台计算
          var sign = Math.abs(p1) / p1; //保存符号
          var F1 = (1 / 2) * m * p1 * p1;
          var F2 = (1 / 2) * m * p2 * p2;
          var F0 = (F1 + F2) / 2;
          V = (a / 6) * (F1 + F2 + 4 * F0) * sign;
        }
        return new work().set(V);
      } else {
        //如果角点异号需要线性插值零点
        var ap1 = (p1 * a) / (Math.abs(p1) + Math.abs(p2)); //格点1分到的边长
        var ap2 = (p2 * a) / (Math.abs(p1) + Math.abs(p2)); //格点2分到的边长
        // var sign1 = p1 / Math.abs(p1);
        // var sign2 = p2 / Math.abs(p2);
        //ap中带了正负号,这一段不要

        var V1 = (ap1 / 6) * m * p1 * p1;
        var V2 = (ap2 / 6) * m * p2 * p2;
        var result = new work();
        if (V1 > 0) return result.init(V2, V1);
        else return result.init(V1, V2);
      }
    }
    //按照四边形底面计算
    function CalCorner(h) {
      if (h == 0) return new work();
      var V = ((Math.pow(m * h, 2) * 1) / 3) * h;
      result = new work();
      result.set(V);
      return result;
    }
    // 计算方形格点内部的挖填量
    // 传入一个2X2的方格
    function CalInGrid(d) {
      var result = new work();
      var sum = sumAbs(d);
      if (checkFourCorner(d)) {
        //如果数组同号的话
        var sign = d[0] / Math.abs(d[0]);
        var V = (Math.pow(a, 2) / 4) * sum * sign;
        result.set(V);
      } else {
        //如果数组异号的话需要分成两组求
        var PArr = GetPositives(d);
        var NArr = GetNegatives(d);
        var V1 = Math.pow(a, 2) / 4 * Math.pow(sumAbs(PArr), 2) / sum;
        var V2 = Math.pow(a, 2) / 4 * Math.pow(sumAbs(NArr), 2) / sum * -1;
        result.init(V1, V2);
      }
      return result;
    }
    //检查四个格点是否都同号
    function checkFourCorner(d) {
      for (var i = 0; i < d.length - 1; i++) {
        if (!checkSign(d[i], d[i + 1]))
          return false;
      }
      return true;
    }
    //绝对值求和
    function sumAbs(d) {
      return d.length <= 1 ? Math.abs(d) : d.reduce(function (x, y) {
        return Math.abs(x) + Math.abs(y);
      });
    }
    //获取正数数列
    function GetPositives(d) {
      var arr = [];
      d.forEach(item => {
        if (item > 0) arr.push(item);
      });
      return arr;
    }
    //获取负数数列
    function GetNegatives(d) {
      var arr = [];
      d.forEach(item => {
        if (item < 0) arr.push(item);
      });
      return arr;
    }
    //检查两个数是否同号
    function checkSign(a, b) {
      if (a * b >= 0) return true;
      else return false;
    }
    //检查哪个点为0,返回不为0的点
    function checkZero(a, b) {
      return a != 0 ? a : b;
    }

    //挖填对象
    function work() {
      this.dig = 0;
      this.fill = 0;
      this.init = function (a, b) {
        a = a.toFixed(3);
        b = b.toFixed(3);
        //dig是正数,fill时负数
        if (a >= 0) this.dig = a;
        else this.fill = a;
        if (b >= 0) this.dig = b;
        else this.fill = b;
        return this;
      };
      this.set = function (value) {
        value = value.toFixed(3);
        if (value > 0) this.dig = value;
        else this.fill = value;
        return this;
      };
      this.add = function (work) {
        this.dig += work.dig;
        this.fill += work.fill;
      };
      this.toString = function () {
        return "开挖土方:" + this.dig + "<br />填充土方:" + this.fill;
      };
      this.toString = function (str) {
        return str + "处开挖土方:" + this.dig + "<br />填充土方:" + this.fill;
      };
    }
  </script>
</body>

</html>

软件计算结果校验

程序中有对其每一部分的计算结果进行跟踪
跟踪结果与计算结果如图所示

计算结果

计算结果

其中主页面下侧为总计算结果,右边控制台输出结果与前一步的插值,为单步计算的结果,控制台对每一步结棍都进行了求和

方格的计算顺序是从左至右,从上至下

四个角点计算顺序是 左上 右上 左下 右下

边的计算顺序是,上 下 左 右

我通过手算进行了计算核对,每一步的手算和机算的误差都在 0.0001 内,其他的误差可能是javascript程序语言中对小数储存的方式而引起的系统误差,验证计算结果正确,程序可以使用。

由于只只有我用一道题目做了手算和机算的相互验证,因此结果可能具有偶然性,欢迎大家辅助验证程序,并欢迎留言指正

计算程序地址

计算挖填方量

引用Reference