예제 #1
0
void Group::AssembleLoops(bool *allClosed,
                          bool *allCoplanar,
                          bool *allNonZeroLen)
{
    SBezierList sbl = {};

    int i;
    for(i = 0; i < SK.entity.n; i++) {
        Entity *e = &(SK.entity.elem[i]);
        if(e->group.v != h.v) continue;
        if(e->construction) continue;
        if(e->forceHidden) continue;

        e->GenerateBezierCurves(&sbl);
    }

    SBezier *sb;
    *allNonZeroLen = true;
    for(sb = sbl.l.First(); sb; sb = sbl.l.NextAfter(sb)) {
        for(i = 1; i <= sb->deg; i++) {
            if(!(sb->ctrl[i]).Equals(sb->ctrl[0])) {
                break;
            }
        }
        if(i > sb->deg) {
            // This is a zero-length edge.
            *allNonZeroLen = false;
            polyError.errorPointAt = sb->ctrl[0];
            goto done;
        }
    }

    // Try to assemble all these Beziers into loops. The closed loops go into
    // bezierLoops, with the outer loops grouped with their holes. The
    // leftovers, if any, go in bezierOpens.
    bezierLoops.FindOuterFacesFrom(&sbl, &polyLoops, NULL,
                                   SS.ChordTolMm(),
                                   allClosed, &(polyError.notClosedAt),
                                   allCoplanar, &(polyError.errorPointAt),
                                   &bezierOpens);
    done:
    sbl.Clear();
}
예제 #2
0
void Entity::GenerateEdges(SEdgeList *el, bool includingConstruction) {
    if(construction && !includingConstruction) return;

    SBezierList sbl;
    ZERO(&sbl);
    GenerateBezierCurves(&sbl);

    int i, j;
    for(i = 0; i < sbl.l.n; i++) {
        SBezier *sb = &(sbl.l.elem[i]);

        List<Vector> lv;
        ZERO(&lv);
        sb->MakePwlInto(&lv);
        for(j = 1; j < lv.n; j++) {
            el->AddEdge(lv.elem[j-1], lv.elem[j], style.v);
        }
        lv.Clear();
    }

    sbl.Clear();
}
예제 #3
0
hEntity GraphicsWindow::SplitCubic(hEntity he, Vector pinter) {
    // Save the original endpoints, since we're about to delete this entity.
    Entity *e01 = SK.GetEntity(he);
    SBezierList sbl;
    ZERO(&sbl);
    e01->GenerateBezierCurves(&sbl);

    hEntity hep0 = e01->point[0],
            hep1 = e01->point[3+e01->extraPoints],
            hep0n = Entity::NO_ENTITY, // the new start point
            hep1n = Entity::NO_ENTITY, // the new finish point
            hepin = Entity::NO_ENTITY; // the intersection point

    // The curve may consist of multiple cubic segments. So find which one
    // contains the intersection point.
    double t;
    int i, j;
    for(i = 0; i < sbl.l.n; i++) {
        SBezier *sb = &(sbl.l.elem[i]);
        if(sb->deg != 3) oops();

        sb->ClosestPointTo(pinter, &t, false);
        if(pinter.Equals(sb->PointAt(t))) {
            // Split that segment at the intersection.
            SBezier b0i, bi1, b01 = *sb;
            b01.SplitAt(t, &b0i, &bi1);

            // Add the two cubic segments this one gets split into.
            hRequest r0i = AddRequest(Request::CUBIC, false),
                     ri1 = AddRequest(Request::CUBIC, false);
            // Don't get entities till after adding, realloc issues

            Entity *e0i = SK.GetEntity(r0i.entity(0)),
                   *ei1 = SK.GetEntity(ri1.entity(0));

            for(j = 0; j <= 3; j++) {
                SK.GetEntity(e0i->point[j])->PointForceTo(b0i.ctrl[j]);
            }
            for(j = 0; j <= 3; j++) {
                SK.GetEntity(ei1->point[j])->PointForceTo(bi1.ctrl[j]);
            }

            Constraint::ConstrainCoincident(e0i->point[3], ei1->point[0]);
            if(i == 0) hep0n = e0i->point[0];
            hep1n = ei1->point[3];
            hepin = e0i->point[3];
        } else {
            hRequest r = AddRequest(Request::CUBIC, false);
            Entity *e = SK.GetEntity(r.entity(0));

            for(j = 0; j <= 3; j++) {
                SK.GetEntity(e->point[j])->PointForceTo(sb->ctrl[j]);
            }

            if(i == 0) hep0n = e->point[0];
            hep1n = e->point[3];
        }
    }

    sbl.Clear();

    ReplacePointInConstraints(hep0, hep0n);
    ReplacePointInConstraints(hep1, hep1n);
    return hepin;
}
예제 #4
0
void StepFileWriter::ExportSurfacesTo(char *file) {
    Group *g = SK.GetGroup(SS.GW.activeGroup);
    SShell *shell = &(g->runningShell);

    if(shell->surface.n == 0) {
        Error("The model does not contain any surfaces to export.%s",
            g->runningMesh.l.n > 0 ?
                "\n\nThe model does contain triangles from a mesh, but "
                "a triangle mesh cannot be exported as a STEP file. Try "
                "File -> Export Mesh... instead." : "");
        return;
    }

    f = fopen(file, "wb");
    if(!f) {
        Error("Couldn't write to '%s'", file);
        return;
    }

    WriteHeader();
	WriteProductHeader();

    ZERO(&advancedFaces);

    SSurface *ss;
    for(ss = shell->surface.First(); ss; ss = shell->surface.NextAfter(ss)) {
        if(ss->trim.n == 0) continue;

        // Get all of the loops of Beziers that trim our surface (with each
        // Bezier split so that we use the section as t goes from 0 to 1), and
        // the piecewise linearization of those loops in xyz space.
        SBezierList sbl;
        ZERO(&sbl);
        ss->MakeSectionEdgesInto(shell, NULL, &sbl);

        // Apply the export scale factor.
        ss->ScaleSelfBy(1.0/SS.exportScale);
        sbl.ScaleSelfBy(1.0/SS.exportScale);

        ExportSurface(ss, &sbl);

        sbl.Clear();
    }

    fprintf(f, "#%d=CLOSED_SHELL('',(", id);
    int *af;
    for(af = advancedFaces.First(); af; af = advancedFaces.NextAfter(af)) {
        fprintf(f, "#%d", *af);
        if(advancedFaces.NextAfter(af) != NULL) fprintf(f, ",");
    }
    fprintf(f, "));\n");
    fprintf(f, "#%d=MANIFOLD_SOLID_BREP('brep',#%d);\n", id+1, id);
    fprintf(f, "#%d=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#%d,#170),#168);\n",
        id+2, id+1);
    fprintf(f, "#%d=SHAPE_REPRESENTATION_RELATIONSHIP($,$,#169,#%d);\n",
        id+3, id+2);

    WriteFooter();

    fclose(f);
    advancedFaces.Clear();
}
예제 #5
0
void SolveSpace::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *sm,
                                    Vector u, Vector v, Vector n,
                                        Vector origin, double cameraTan,
                                    VectorFileWriter *out)
{
    double s = 1.0 / SS.exportScale;

    // Project into the export plane; so when we're done, z doesn't matter,
    // and x and y are what goes in the DXF.
    SEdge *e;
    for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
        // project into the specified csys, and apply export scale
        (e->a) = e->a.InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
        (e->b) = e->b.InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
    }

    SBezier *b;
    if(sbl) {
        for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
            *b = b->InPerspective(u, v, n, origin, cameraTan);
            int i;
            for(i = 0; i <= b->deg; i++) {
                b->ctrl[i] = (b->ctrl[i]).ScaledBy(s);
            }
        }
    }

    // If cutter radius compensation is requested, then perform it now
    if(fabs(SS.exportOffset) > LENGTH_EPS) {
        // assemble those edges into a polygon, and clear the edge list
        SPolygon sp;
        ZERO(&sp);
        sel->AssemblePolygon(&sp, NULL);
        sel->Clear();

        SPolygon compd;
        ZERO(&compd);
        sp.normal = Vector::From(0, 0, -1);
        sp.FixContourDirections();
        sp.OffsetInto(&compd, SS.exportOffset*s);
        sp.Clear();

        compd.MakeEdgesInto(sel);
        compd.Clear();
    }

    // Now the triangle mesh; project, then build a BSP to perform
    // occlusion testing and generated the shaded surfaces.
    SMesh smp;
    ZERO(&smp);
    if(sm) {
        Vector l0 = (SS.lightDir[0]).WithMagnitude(1),
               l1 = (SS.lightDir[1]).WithMagnitude(1);
        STriangle *tr;
        for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) {
            STriangle tt = *tr;
            tt.a = (tt.a).InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
            tt.b = (tt.b).InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
            tt.c = (tt.c).InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);

            // And calculate lighting for the triangle
            Vector n = tt.Normal().WithMagnitude(1);
            double lighting = SS.ambientIntensity +
                                  max(0, (SS.lightIntensity[0])*(n.Dot(l0))) +
                                  max(0, (SS.lightIntensity[1])*(n.Dot(l1)));
            double r = min(1, REDf  (tt.meta.color)*lighting),
                   g = min(1, GREENf(tt.meta.color)*lighting),
                   b = min(1, BLUEf (tt.meta.color)*lighting);
            tt.meta.color = RGBf(r, g, b);
            smp.AddTriangle(&tt);
        }
    }

    // Use the BSP routines to generate the split triangles in paint order.
    SBsp3 *bsp = SBsp3::FromMesh(&smp);
    SMesh sms;
    ZERO(&sms);
    bsp->GenerateInPaintOrder(&sms);
    // And cull the back-facing triangles
    STriangle *tr;
    sms.l.ClearTags();
    for(tr = sms.l.First(); tr; tr = sms.l.NextAfter(tr)) {
        Vector n = tr->Normal();
        if(n.z < 0) {
            tr->tag = 1;
        }
    }
    sms.l.RemoveTagged();

    // And now we perform hidden line removal if requested
    SEdgeList hlrd;
    ZERO(&hlrd);
    if(sm && !SS.GW.showHdnLines) {
        SKdNode *root = SKdNode::From(&smp);

        // Generate the edges where a curved surface turns from front-facing
        // to back-facing.
        if(SS.GW.showEdges) {
            root->MakeCertainEdgesInto(sel, SKdNode::TURNING_EDGES,
                        false, NULL, NULL);
        }

        root->ClearTags();
        int cnt = 1234;

        SEdge *se;
        for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
            if(se->auxA == Style::CONSTRAINT) {
                // Constraints should not get hidden line removed; they're
                // always on top.
                hlrd.AddEdge(se->a, se->b, se->auxA);
                continue;
            }

            SEdgeList out;
            ZERO(&out);
            // Split the original edge against the mesh
            out.AddEdge(se->a, se->b, se->auxA);
            root->OcclusionTestLine(*se, &out, cnt);
            // the occlusion test splits unnecessarily; so fix those
            out.MergeCollinearSegments(se->a, se->b);
            cnt++;
            // And add the results to our output
            SEdge *sen;
            for(sen = out.l.First(); sen; sen = out.l.NextAfter(sen)) {
                hlrd.AddEdge(sen->a, sen->b, sen->auxA);
            }
            out.Clear();
        }

        sel = &hlrd;
    }

    // We kept the line segments and Beziers separate until now; but put them
    // all together, and also project everything into the xy plane, since not
    // all export targets ignore the z component of the points.
    for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
        SBezier sb = SBezier::From(e->a, e->b);
        sb.auxA = e->auxA;
        sbl->l.Add(&sb);
    }
    for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
        for(int i = 0; i <= b->deg; i++) {
            b->ctrl[i].z = 0;
        }
    }

    // If possible, then we will assemble these output curves into loops. They
    // will then get exported as closed paths.
    SBezierLoopSetSet sblss;
    ZERO(&sblss);
    SBezierList leftovers;
    ZERO(&leftovers);
    SSurface srf = SSurface::FromPlane(Vector::From(0, 0, 0),
                                       Vector::From(1, 0, 0),
                                       Vector::From(0, 1, 0));
    SPolygon spxyz;
    ZERO(&spxyz);
    bool allClosed;
    SEdge notClosedAt;
    sbl->l.ClearTags();
    sblss.FindOuterFacesFrom(sbl, &spxyz, &srf,
                             SS.ChordTolMm()*s,
                             &allClosed, &notClosedAt,
                             NULL, NULL,
                             &leftovers);
    for(b = leftovers.l.First(); b; b = leftovers.l.NextAfter(b)) {
        sblss.AddOpenPath(b);
    }

    // Now write the lines and triangles to the output file
    out->Output(&sblss, &sms);

    leftovers.Clear();
    spxyz.Clear();
    sblss.Clear();
    smp.Clear();
    sms.Clear();
    hlrd.Clear();
}
예제 #6
0
void SolveSpace::ExportViewOrWireframeTo(char *filename, bool wireframe) {
    int i;
    SEdgeList edges;
    ZERO(&edges);
    SBezierList beziers;
    ZERO(&beziers);

    SMesh *sm = NULL;
    if(SS.GW.showShaded) {
        Group *g = SK.GetGroup(SS.GW.activeGroup);
        g->GenerateDisplayItems();
        sm = &(g->displayMesh);
    }
    if(sm && sm->IsEmpty()) {
        sm = NULL;
    }

    for(i = 0; i < SK.entity.n; i++) {
        Entity *e = &(SK.entity.elem[i]);
        if(!e->IsVisible()) continue;
        if(e->construction) continue;

        if(SS.exportPwlCurves || (sm && !SS.GW.showHdnLines) ||
                                 fabs(SS.exportOffset) > LENGTH_EPS)
        {
            // We will be doing hidden line removal, which we can't do on
            // exact curves; so we need things broken down to pwls. Same
            // problem with cutter radius compensation.
            e->GenerateEdges(&edges);
        } else {
            e->GenerateBezierCurves(&beziers);
        }
    }

    if(SS.GW.showEdges) {
        Group *g = SK.GetGroup(SS.GW.activeGroup);
        g->GenerateDisplayItems();
        SEdgeList *selr = &(g->displayEdges);
        SEdge *se;
        for(se = selr->l.First(); se; se = selr->l.NextAfter(se)) {
            edges.AddEdge(se->a, se->b, Style::SOLID_EDGE);
        }
    }

    if(SS.GW.showConstraints) {
        Constraint *c;
        for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) {
            c->GetEdges(&edges);
        }
    }

    if(wireframe) {
        VectorFileWriter *out = VectorFileWriter::ForFile(filename);
        if(out) {
            ExportWireframeCurves(&edges, &beziers, out);
        }
    } else {
        Vector u = SS.GW.projRight,
               v = SS.GW.projUp,
               n = u.Cross(v),
               origin = SS.GW.offset.ScaledBy(-1);

        VectorFileWriter *out = VectorFileWriter::ForFile(filename);
        if(out) {
            ExportLinesAndMesh(&edges, &beziers, sm,
                               u, v, n, origin, SS.CameraTangent()*SS.GW.scale,
                               out);
        }

        if(out && !out->HasCanvasSize()) {
            // These file formats don't have a canvas size, so they just
            // get exported in the raw coordinate system. So indicate what
            // that was on-screen.
            SS.justExportedInfo.draw = true;
            SS.justExportedInfo.pt = origin;
            SS.justExportedInfo.u = u;
            SS.justExportedInfo.v = v;
            InvalidateGraphics();
        }
    }

    edges.Clear();
    beziers.Clear();
}
예제 #7
0
void SolveSpace::ExportSectionTo(char *filename) {
    Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
    gn = gn.WithMagnitude(1);

    Group *g = SK.GetGroup(SS.GW.activeGroup);
    g->GenerateDisplayItems();
    if(g->displayMesh.IsEmpty()) {
        Error("No solid model present; draw one with extrudes and revolves, "
              "or use Export 2d View to export bare lines and curves.");
        return;
    }
    
    // The plane in which the exported section lies; need this because we'll
    // reorient from that plane into the xy plane before exporting.
    Vector origin, u, v, n;
    double d;

    SS.GW.GroupSelection();
#define gs (SS.GW.gs)
    if((gs.n == 0 && g->activeWorkplane.v != Entity::FREE_IN_3D.v)) {
        Entity *wrkpl = SK.GetEntity(g->activeWorkplane);
        origin = wrkpl->WorkplaneGetOffset();
        n = wrkpl->Normal()->NormalN();
        u = wrkpl->Normal()->NormalU();
        v = wrkpl->Normal()->NormalV();
    } else if(gs.n == 1 && gs.faces == 1) {
        Entity *face = SK.GetEntity(gs.entity[0]);
        origin = face->FaceGetPointNum();
        n = face->FaceGetNormalNum();
        if(n.Dot(gn) < 0) n = n.ScaledBy(-1);
        u = n.Normal(0);
        v = n.Normal(1);
    } else if(gs.n == 3 && gs.vectors == 2 && gs.points == 1) {
        Vector ut = SK.GetEntity(gs.entity[0])->VectorGetNum(),
               vt = SK.GetEntity(gs.entity[1])->VectorGetNum();
        ut = ut.WithMagnitude(1);
        vt = vt.WithMagnitude(1);

        if(fabs(SS.GW.projUp.Dot(vt)) < fabs(SS.GW.projUp.Dot(ut))) {
            SWAP(Vector, ut, vt);
        }
        if(SS.GW.projRight.Dot(ut) < 0) ut = ut.ScaledBy(-1);
        if(SS.GW.projUp.   Dot(vt) < 0) vt = vt.ScaledBy(-1);

        origin = SK.GetEntity(gs.point[0])->PointGetNum();
        n = ut.Cross(vt);
        u = ut.WithMagnitude(1);
        v = (n.Cross(u)).WithMagnitude(1);
    } else {
        Error("Bad selection for export section. Please select:\n\n"
              "    * nothing, with an active workplane "
                        "(workplane is section plane)\n"
              "    * a face (section plane through face)\n"
              "    * a point and two line segments "
                        "(plane through point and parallel to lines)\n");
        return;
    }
    SS.GW.ClearSelection();

    n = n.WithMagnitude(1);
    d = origin.Dot(n);

    SEdgeList el;
    ZERO(&el);
    SBezierList bl;
    ZERO(&bl);

    // If there's a mesh, then grab the edges from it.
    g->runningMesh.MakeEdgesInPlaneInto(&el, n, d);

    // If there's a shell, then grab the edges and possibly Beziers.
    g->runningShell.MakeSectionEdgesInto(n, d,
       &el, 
       (SS.exportPwlCurves || fabs(SS.exportOffset) > LENGTH_EPS) ? NULL : &bl);

    // All of these are solid model edges, so use the appropriate style.
    SEdge *se;
    for(se = el.l.First(); se; se = el.l.NextAfter(se)) {
        se->auxA = Style::SOLID_EDGE;
    }
    SBezier *sb;
    for(sb = bl.l.First(); sb; sb = bl.l.NextAfter(sb)) {
        sb->auxA = Style::SOLID_EDGE;
    }

    el.CullExtraneousEdges();
    bl.CullIdenticalBeziers();

    // And write the edges.
    VectorFileWriter *out = VectorFileWriter::ForFile(filename);
    if(out) {
        // parallel projection (no perspective), and no mesh
        ExportLinesAndMesh(&el, &bl, NULL,
                           u, v, n, origin, 0,
                           out);
    }
    el.Clear();
    bl.Clear();
}