Esempio n. 1
0
// ------------------------------------------------------------------------------------------------
// Compute the normal of the last polygon in the given mesh
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
{
	size_t total = vertcnt.back(), vidx = verts.size() - total;
	std::vector<IfcFloat> temp((total+2)*3);
	for(size_t vofs = 0, cnt = 0; vofs < total; ++vofs) {
		const IfcVector3& v = verts[vidx+vofs];
		temp[cnt++] = v.x;
		temp[cnt++] = v.y;
		temp[cnt++] = v.z;
	}
	IfcVector3 nor;
	NewellNormal<3,3,3>(nor,total,&temp[0],&temp[1],&temp[2]);
	return normalize ? nor.Normalize() : nor;
}
// ------------------------------------------------------------------------------------------------
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize)
{
	std::vector<IfcFloat> temp((cnt+2)*3);
	for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs )
	{
		const IfcVector3& v = vtcs[vofs];
		temp[i++] = v.x;
		temp[i++] = v.y;
		temp[i++] = v.z;
	}

	IfcVector3 nor;
	NewellNormal<3, 3, 3>(nor, cnt, &temp[0], &temp[1], &temp[2]);
	return normalize ? nor.Normalize() : nor;
}
// ------------------------------------------------------------------------------------------------
void ConvertDirection(IfcVector3& out, const IfcDirection& in)
{
	out = IfcVector3();
	for(size_t i = 0; i < in.DirectionRatios.size(); ++i) {
		out[i] = in.DirectionRatios[i];
	}
	const IfcFloat len = out.Length();
	if (len<1e-6) {
		IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
		return;
	}
	out /= len;
}
Esempio n. 4
0
// ------------------------------------------------------------------------------------------------
IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut)
{
    const std::vector<IfcVector3>& out = curmesh.verts;
    IfcMatrix3 m;

    ok = true;

    // The input "mesh" must be a single polygon
    const size_t s = out.size();
    assert(curmesh.vertcnt.size() == 1 && curmesh.vertcnt.back() == s);

    const IfcVector3 any_point = out[s-1];
    IfcVector3 nor;

    // The input polygon is arbitrarily shaped, therefore we might need some tries
    // until we find a suitable normal. Note that Newell's algorithm would give
    // a more robust result, but this variant also gives us a suitable first
    // axis for the 2D coordinate space on the polygon plane, exploiting the
    // fact that the input polygon is nearly always a quad.
    bool done = false;
    size_t i, j;
    for (i = 0; !done && i < s-2; done || ++i) {
        for (j = i+1; j < s-1; ++j) {
            nor = -((out[i]-any_point)^(out[j]-any_point));
            if(std::fabs(nor.Length()) > 1e-8f) {
                done = true;
                break;
            }
        }
    }

    if(!done) {
        ok = false;
        return m;
    }

    nor.Normalize();
    norOut = nor;

    IfcVector3 r = (out[i]-any_point);
    r.Normalize();

    //if(d) {
    //  *d = -any_point * nor;
    //}

    // Reconstruct orthonormal basis
    // XXX use Gram Schmidt for increased robustness
    IfcVector3 u = r ^ nor;
    u.Normalize();

    m.a1 = r.x;
    m.a2 = r.y;
    m.a3 = r.z;

    m.b1 = u.x;
    m.b2 = u.y;
    m.b3 = u.z;

    m.c1 = -nor.x;
    m.c2 = -nor.y;
    m.c3 = -nor.z;

    return m;
}
Esempio n. 5
0
// ------------------------------------------------------------------------------------------------
void ProcessSweptDiskSolid(const IfcSweptDiskSolid solid, TempMesh& result, ConversionData& conv)
{
    const Curve* const curve = Curve::Convert(*solid.Directrix, conv);
    if(!curve) {
        IFCImporter::LogError("failed to convert Directrix curve (IfcSweptDiskSolid)");
        return;
    }

    const unsigned int cnt_segments = 16;
    const IfcFloat deltaAngle = AI_MATH_TWO_PI/cnt_segments;

    const size_t samples = curve->EstimateSampleCount(solid.StartParam,solid.EndParam);

    result.verts.reserve(cnt_segments * samples * 4);
    result.vertcnt.reserve((cnt_segments - 1) * samples);

    std::vector<IfcVector3> points;
    points.reserve(cnt_segments * samples);

    TempMesh temp;
    curve->SampleDiscrete(temp,solid.StartParam,solid.EndParam);
    const std::vector<IfcVector3>& curve_points = temp.verts;

    if(curve_points.empty()) {
        IFCImporter::LogWarn("curve evaluation yielded no points (IfcSweptDiskSolid)");
        return;
    }

    IfcVector3 current = curve_points[0];
    IfcVector3 previous = current;
    IfcVector3 next;

    IfcVector3 startvec;
    startvec.x = 1.0f;
    startvec.y = 1.0f;
    startvec.z = 1.0f;

    unsigned int last_dir = 0;

    // generate circles at the sweep positions
    for(size_t i = 0; i < samples; ++i) {

        if(i != samples - 1) {
            next = curve_points[i + 1];
        }

        // get a direction vector reflecting the approximate curvature (i.e. tangent)
        IfcVector3 d = (current-previous) + (next-previous);

        d.Normalize();

        // figure out an arbitrary point q so that (p-q) * d = 0,
        // try to maximize ||(p-q)|| * ||(p_last-q_last)||
        IfcVector3 q;
        bool take_any = false;

        for (unsigned int i = 0; i < 2; ++i, take_any = true) {
            if ((last_dir == 0 || take_any) && std::abs(d.x) > 1e-6) {
                q.y = startvec.y;
                q.z = startvec.z;
                q.x = -(d.y * q.y + d.z * q.z) / d.x;
                last_dir = 0;
                break;
            }
            else if ((last_dir == 1 || take_any) && std::abs(d.y) > 1e-6) {
                q.x = startvec.x;
                q.z = startvec.z;
                q.y = -(d.x * q.x + d.z * q.z) / d.y;
                last_dir = 1;
                break;
            }
            else if ((last_dir == 2 && std::abs(d.z) > 1e-6) || take_any) {
                q.y = startvec.y;
                q.x = startvec.x;
                q.z = -(d.y * q.y + d.x * q.x) / d.z;
                last_dir = 2;
                break;
            }
        }

        q *= solid.Radius / q.Length();
        startvec = q;

        // generate a rotation matrix to rotate q around d
        IfcMatrix4 rot;
        IfcMatrix4::Rotation(deltaAngle,d,rot);

        for (unsigned int seg = 0; seg < cnt_segments; ++seg, q *= rot ) {
            points.push_back(q + current);
        }

        previous = current;
        current = next;
    }

    // make quads
    for(size_t i = 0; i < samples - 1; ++i) {

        const aiVector3D& this_start = points[ i * cnt_segments ];

        // locate corresponding point on next sample ring
        unsigned int best_pair_offset = 0;
        float best_distance_squared = 1e10f;
        for (unsigned int seg = 0; seg < cnt_segments; ++seg) {
            const aiVector3D& p = points[ (i+1) * cnt_segments + seg];
            const float l = (p-this_start).SquareLength();

            if(l < best_distance_squared) {
                best_pair_offset = seg;
                best_distance_squared = l;
            }
        }

        for (unsigned int seg = 0; seg < cnt_segments; ++seg) {

            result.verts.push_back(points[ i * cnt_segments + (seg % cnt_segments)]);
            result.verts.push_back(points[ i * cnt_segments + (seg + 1) % cnt_segments]);
            result.verts.push_back(points[ (i+1) * cnt_segments + ((seg + 1 + best_pair_offset) % cnt_segments)]);
            result.verts.push_back(points[ (i+1) * cnt_segments + ((seg + best_pair_offset) % cnt_segments)]);

            IfcVector3& v1 = *(result.verts.end()-1);
            IfcVector3& v2 = *(result.verts.end()-2);
            IfcVector3& v3 = *(result.verts.end()-3);
            IfcVector3& v4 = *(result.verts.end()-4);

            if (((v4-v3) ^ (v4-v1)) * (v4 - curve_points[i]) < 0.0f) {
                std::swap(v4, v1);
                std::swap(v3, v2);
            }

            result.vertcnt.push_back(4);
        }
    }

    IFCImporter::LogDebug("generate mesh procedurally by sweeping a disk along a curve (IfcSweptDiskSolid)");
}