<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkColorFilter.h"
#include "SkMultiPictureDraw.h"
#include "SkPictureRecorder.h"
#include "SkSurface.h"

static const SkScalar kRoot3Over2 = 0.86602545f;  // sin(60)

static const int kHexSide = 30;
static const int kNumHexX = 6;
static const int kNumHexY = 6;
static const int kPicWidth = kNumHexX * kHexSide;
static const int kPicHeight = SkScalarCeilToInt((kNumHexY - 0.5f) * 2 * kHexSide * kRoot3Over2);
static const SkScalar kInset = 20.0f;

// Create a hexagon centered at (originX, originY)
static SkPath make_hex_path(SkScalar originX, SkScalar originY) {
    SkPath hex;
    hex.moveTo(originX-kHexSide, originY);
    hex.rLineTo(SkScalarHalf(kHexSide), kRoot3Over2 * kHexSide);
    hex.rLineTo(SkIntToScalar(kHexSide), 0);
    hex.rLineTo(SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
    hex.rLineTo(-SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
    hex.rLineTo(-SkIntToScalar(kHexSide), 0);
    hex.close();
    return hex;
}

// Make a picture that is a tiling of the plane with stroked hexagons where
// each hexagon is in its own layer. The layers are to exercise Ganesh's
// layer hoisting.
static const SkPicture* make_picture(SkColor fillColor) {

    // Create a hexagon with its center at the origin
    SkPath hex = make_hex_path(0, 0);

    SkPaint fill;
    fill.setStyle(SkPaint::kFill_Style);
    fill.setColor(fillColor);

    SkPaint stroke;
    stroke.setStyle(SkPaint::kStroke_Style);
    stroke.setStrokeWidth(3);

    SkPictureRecorder recorder;

    SkCanvas* canvas = recorder.beginRecording(kPicWidth, kPicHeight);

    SkScalar xPos, yPos = 0;

    for (int y = 0; y < kNumHexY; ++y) {
        xPos = 0;

        for (int x = 0; x < kNumHexX; ++x) {
            canvas->saveLayer(NULL, NULL);
            canvas->translate(xPos, yPos + ((x % 2) ? kRoot3Over2 * kHexSide : 0));
            canvas->drawPath(hex, fill);
            canvas->drawPath(hex, stroke);
            canvas->restore();

            xPos += 1.5f * kHexSide;
        }

        yPos += 2 * kHexSide * kRoot3Over2;
    }

    return recorder.endRecording();
}

static SkSurface* create_compat_surface(SkCanvas* canvas, int width, int height) {
    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);

    SkSurface* surface = canvas->newSurface(info);
    if (NULL == surface) {
        // picture canvas returns NULL so fall back to raster
        surface = SkSurface::NewRaster(info);
    }

    return surface;
}

// This class stores the information required to compose all the result
// fragments potentially generated by the MultiPictureDraw object
class ComposeStep {
public:
    ComposeStep() : fSurf(NULL), fX(0.0f), fY(0.0f), fPaint(NULL) { }
    ~ComposeStep() { SkSafeUnref(fSurf);  SkDELETE(fPaint); }

    SkSurface* fSurf;
    SkScalar   fX;
    SkScalar   fY;
    SkPaint*   fPaint;
};

typedef void (*PFContentMtd)(SkCanvas* canvas, const SkPicture* pictures[2]);

// Just a single picture with no clip
static void no_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);
}

// Two pictures with a rect clip on the second one
static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    SkRect rect = SkRect::MakeWH(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight));
    rect.inset(kInset, kInset);

    canvas->clipRect(rect);

    canvas->drawPicture(pictures[1]);
}

// Two pictures with a round rect clip on the second one
static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    SkRect rect = SkRect::MakeWH(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight));
    rect.inset(kInset, kInset);

    SkRRect rrect;
    rrect.setRectXY(rect, kInset, kInset);

    canvas->clipRRect(rrect);

    canvas->drawPicture(pictures[1]);
}

// Two pictures with a clip path on the second one
static void path_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    // Create a hexagon centered on the middle of the hex grid
    SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);

    canvas->clipPath(hex);

    canvas->drawPicture(pictures[1]);
}

// Two pictures with an inverse clip path on the second one
static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    // Create a hexagon centered on the middle of the hex grid
    SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);
    hex.setFillType(SkPath::kInverseEvenOdd_FillType);

    canvas->clipPath(hex);

    canvas->drawPicture(pictures[1]);
}

static const PFContentMtd gContentMthds[] = {
    no_clip,
    rect_clip,
    rrect_clip,
    path_clip,
    invpath_clip
};

static void create_content(SkMultiPictureDraw* mpd, PFContentMtd pfGen,
                           const SkPicture* pictures[2],
                           SkCanvas* dest, const SkMatrix& xform) {
    SkAutoTUnref<SkPicture> composite;

    {
        SkPictureRecorder recorder;

        SkCanvas* pictureCanvas = recorder.beginRecording(kPicWidth, kPicHeight);

        (*pfGen)(pictureCanvas, pictures);

        composite.reset(recorder.endRecording());
    }

    mpd->add(dest, composite, &xform);
}

typedef void(*PFLayoutMtd)(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
                           PFContentMtd pfGen, const SkPicture* pictures[2],
                           SkTArray<ComposeStep>* composeSteps);

// Draw the content into a single canvas
static void simple(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
                   PFContentMtd pfGen,
                   const SkPicture* pictures[2],
                   SkTArray<ComposeStep> *composeSteps) {

    ComposeStep& step = composeSteps->push_back();

    step.fSurf = create_compat_surface(finalCanvas, kPicWidth, kPicHeight);

    SkCanvas* subCanvas = step.fSurf->getCanvas();

    create_content(mpd, pfGen, pictures, subCanvas, SkMatrix::I());
}

// Draw the content into multiple canvases/tiles
static void tiled(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
                  PFContentMtd pfGen,
                  const SkPicture* pictures[2],
                  SkTArray<ComposeStep> *composeSteps) {
    static const int kNumTilesX = 2;
    static const int kNumTilesY = 2;
    static const int kTileWidth = kPicWidth / kNumTilesX;
    static const int kTileHeight = kPicHeight / kNumTilesY;

    SkASSERT(kPicWidth == kNumTilesX * kTileWidth);
    SkASSERT(kPicHeight == kNumTilesY * kTileHeight);

    static const SkColor colors[kNumTilesX][kNumTilesY] = {
        { SK_ColorCYAN,   SK_ColorMAGENTA },
        { SK_ColorYELLOW, SK_ColorGREEN   }
    };

    for (int y = 0; y < kNumTilesY; ++y) {
        for (int x = 0; x < kNumTilesX; ++x) {
            ComposeStep& step = composeSteps->push_back();

            step.fX = SkIntToScalar(x*kTileWidth);
            step.fY = SkIntToScalar(y*kTileHeight);
            step.fPaint = SkNEW(SkPaint);
            step.fPaint->setColorFilter(
                SkColorFilter::CreateModeFilter(colors[x][y], SkXfermode::kModulate_Mode))->unref();

            step.fSurf = create_compat_surface(finalCanvas, kTileWidth, kTileHeight);

            SkCanvas* subCanvas = step.fSurf->getCanvas();

            SkMatrix trans;
            trans.setTranslate(-SkIntToScalar(x*kTileWidth), -SkIntToScalar(y*kTileHeight));

            create_content(mpd, pfGen, pictures, subCanvas, trans);
        }
    }
}

static const PFLayoutMtd gLayoutMthds[] = { simple, tiled };

namespace skiagm {
    /**
     * This GM exercises the SkMultiPictureDraw object. It tests the
     * cross product of:
     *      tiled vs. all-at-once rendering (e.g., into many or just 1 canvas)
     *      different clips (e.g., none, rect, rrect)
     *      single vs. multiple pictures (e.g., normal vs. picture-pile-style content)
     */
    class MultiPictureDraw : public GM {
    public:
        enum Content {
            kNoClipSingle_Content,
            kRectClipMulti_Content,
            kRRectClipMulti_Content,
            kPathClipMulti_Content,
            kInvPathClipMulti_Content,

            kLast_Content = kInvPathClipMulti_Content
        };

        static const int kContentCnt = kLast_Content + 1;

        enum Layout {
            kSimple_Layout,
            kTiled_Layout,

            kLast_Layout = kTiled_Layout
        };

        static const int kLayoutCnt = kLast_Layout + 1;

        MultiPictureDraw(Content content, Layout layout) : fContent(content), fLayout(layout) {
            SkASSERT(SK_ARRAY_COUNT(gLayoutMthds) == kLayoutCnt);
            SkASSERT(SK_ARRAY_COUNT(gContentMthds) == kContentCnt);

            fPictures[0] = fPictures[1] = NULL;
        }

        virtual ~MultiPictureDraw() {
            SkSafeUnref(fPictures[0]);
            SkSafeUnref(fPictures[1]);
        }

    protected:
        Content          fContent;
        Layout           fLayout;
        const SkPicture* fPictures[2];

        virtual void onOnceBeforeDraw() SK_OVERRIDE {
            fPictures[0] = SkRef(make_picture(SK_ColorWHITE));
            fPictures[1] = SkRef(make_picture(SK_ColorGRAY));
        }

        virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE{
            SkMultiPictureDraw mpd;
            SkTArray<ComposeStep> composeSteps;

            // Fill up the MultiPictureDraw
            (*gLayoutMthds[fLayout])(canvas, &mpd,
                                     gContentMthds[fContent],
                                     fPictures, &composeSteps);

            mpd.draw();

            // Compose all the drawn canvases into the final canvas
            for (int i = 0; i < composeSteps.count(); ++i) {
                const ComposeStep& step = composeSteps[i];

                SkAutoTUnref<SkImage> image(step.fSurf->newImageSnapshot());

                image->draw(canvas, step.fX, step.fY, step.fPaint);
            }
        }

        virtual SkISize onISize() SK_OVERRIDE{ return SkISize::Make(kPicWidth, kPicHeight); }

        virtual SkString onShortName() SK_OVERRIDE{
            static const char* gContentNames[] = {
                "noclip", "rectclip", "rrectclip", "pathclip", "invpathclip"
            };
            static const char* gLayoutNames[] = { "simple", "tiled" };

            SkASSERT(SK_ARRAY_COUNT(gLayoutNames) == kLayoutCnt);
            SkASSERT(SK_ARRAY_COUNT(gContentNames) == kContentCnt);

            SkString name("multipicturedraw_");

            name.append(gContentNames[fContent]);
            name.append("_");
            name.append(gLayoutNames[fLayout]);
            return name;
        }

        virtual uint32_t onGetFlags() const SK_OVERRIDE { return kAsBench_Flag | kSkipTiled_Flag; }

    private:
        typedef GM INHERITED;
    };

    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kNoClipSingle_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRectClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRRectClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kPathClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kInvPathClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)

    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kNoClipSingle_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRectClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRRectClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kPathClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kInvPathClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
}
<commit_msg>Fix leak in multipicturedraw GMs.<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkColorFilter.h"
#include "SkMultiPictureDraw.h"
#include "SkPictureRecorder.h"
#include "SkSurface.h"

static const SkScalar kRoot3Over2 = 0.86602545f;  // sin(60)

static const int kHexSide = 30;
static const int kNumHexX = 6;
static const int kNumHexY = 6;
static const int kPicWidth = kNumHexX * kHexSide;
static const int kPicHeight = SkScalarCeilToInt((kNumHexY - 0.5f) * 2 * kHexSide * kRoot3Over2);
static const SkScalar kInset = 20.0f;

// Create a hexagon centered at (originX, originY)
static SkPath make_hex_path(SkScalar originX, SkScalar originY) {
    SkPath hex;
    hex.moveTo(originX-kHexSide, originY);
    hex.rLineTo(SkScalarHalf(kHexSide), kRoot3Over2 * kHexSide);
    hex.rLineTo(SkIntToScalar(kHexSide), 0);
    hex.rLineTo(SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
    hex.rLineTo(-SkScalarHalf(kHexSide), -kHexSide * kRoot3Over2);
    hex.rLineTo(-SkIntToScalar(kHexSide), 0);
    hex.close();
    return hex;
}

// Make a picture that is a tiling of the plane with stroked hexagons where
// each hexagon is in its own layer. The layers are to exercise Ganesh's
// layer hoisting.
static const SkPicture* make_picture(SkColor fillColor) {

    // Create a hexagon with its center at the origin
    SkPath hex = make_hex_path(0, 0);

    SkPaint fill;
    fill.setStyle(SkPaint::kFill_Style);
    fill.setColor(fillColor);

    SkPaint stroke;
    stroke.setStyle(SkPaint::kStroke_Style);
    stroke.setStrokeWidth(3);

    SkPictureRecorder recorder;

    SkCanvas* canvas = recorder.beginRecording(kPicWidth, kPicHeight);

    SkScalar xPos, yPos = 0;

    for (int y = 0; y < kNumHexY; ++y) {
        xPos = 0;

        for (int x = 0; x < kNumHexX; ++x) {
            canvas->saveLayer(NULL, NULL);
            canvas->translate(xPos, yPos + ((x % 2) ? kRoot3Over2 * kHexSide : 0));
            canvas->drawPath(hex, fill);
            canvas->drawPath(hex, stroke);
            canvas->restore();

            xPos += 1.5f * kHexSide;
        }

        yPos += 2 * kHexSide * kRoot3Over2;
    }

    return recorder.endRecording();
}

static SkSurface* create_compat_surface(SkCanvas* canvas, int width, int height) {
    SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);

    SkSurface* surface = canvas->newSurface(info);
    if (NULL == surface) {
        // picture canvas returns NULL so fall back to raster
        surface = SkSurface::NewRaster(info);
    }

    return surface;
}

// This class stores the information required to compose all the result
// fragments potentially generated by the MultiPictureDraw object
class ComposeStep {
public:
    ComposeStep() : fSurf(NULL), fX(0.0f), fY(0.0f), fPaint(NULL) { }
    ~ComposeStep() { SkSafeUnref(fSurf);  SkDELETE(fPaint); }

    SkSurface* fSurf;
    SkScalar   fX;
    SkScalar   fY;
    SkPaint*   fPaint;
};

typedef void (*PFContentMtd)(SkCanvas* canvas, const SkPicture* pictures[2]);

// Just a single picture with no clip
static void no_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);
}

// Two pictures with a rect clip on the second one
static void rect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    SkRect rect = SkRect::MakeWH(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight));
    rect.inset(kInset, kInset);

    canvas->clipRect(rect);

    canvas->drawPicture(pictures[1]);
}

// Two pictures with a round rect clip on the second one
static void rrect_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    SkRect rect = SkRect::MakeWH(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight));
    rect.inset(kInset, kInset);

    SkRRect rrect;
    rrect.setRectXY(rect, kInset, kInset);

    canvas->clipRRect(rrect);

    canvas->drawPicture(pictures[1]);
}

// Two pictures with a clip path on the second one
static void path_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    // Create a hexagon centered on the middle of the hex grid
    SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);

    canvas->clipPath(hex);

    canvas->drawPicture(pictures[1]);
}

// Two pictures with an inverse clip path on the second one
static void invpath_clip(SkCanvas* canvas, const SkPicture* pictures[2]) {
    canvas->drawPicture(pictures[0]);

    // Create a hexagon centered on the middle of the hex grid
    SkPath hex = make_hex_path((kNumHexX / 2.0f) * kHexSide, kNumHexY * kHexSide * kRoot3Over2);
    hex.setFillType(SkPath::kInverseEvenOdd_FillType);

    canvas->clipPath(hex);

    canvas->drawPicture(pictures[1]);
}

static const PFContentMtd gContentMthds[] = {
    no_clip,
    rect_clip,
    rrect_clip,
    path_clip,
    invpath_clip
};

static void create_content(SkMultiPictureDraw* mpd, PFContentMtd pfGen,
                           const SkPicture* pictures[2],
                           SkCanvas* dest, const SkMatrix& xform) {
    SkAutoTUnref<SkPicture> composite;

    {
        SkPictureRecorder recorder;

        SkCanvas* pictureCanvas = recorder.beginRecording(kPicWidth, kPicHeight);

        (*pfGen)(pictureCanvas, pictures);

        composite.reset(recorder.endRecording());
    }

    mpd->add(dest, composite, &xform);
}

typedef void(*PFLayoutMtd)(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
                           PFContentMtd pfGen, const SkPicture* pictures[2],
                           SkTArray<ComposeStep>* composeSteps);

// Draw the content into a single canvas
static void simple(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
                   PFContentMtd pfGen,
                   const SkPicture* pictures[2],
                   SkTArray<ComposeStep> *composeSteps) {

    ComposeStep& step = composeSteps->push_back();

    step.fSurf = create_compat_surface(finalCanvas, kPicWidth, kPicHeight);

    SkCanvas* subCanvas = step.fSurf->getCanvas();

    create_content(mpd, pfGen, pictures, subCanvas, SkMatrix::I());
}

// Draw the content into multiple canvases/tiles
static void tiled(SkCanvas* finalCanvas, SkMultiPictureDraw* mpd,
                  PFContentMtd pfGen,
                  const SkPicture* pictures[2],
                  SkTArray<ComposeStep> *composeSteps) {
    static const int kNumTilesX = 2;
    static const int kNumTilesY = 2;
    static const int kTileWidth = kPicWidth / kNumTilesX;
    static const int kTileHeight = kPicHeight / kNumTilesY;

    SkASSERT(kPicWidth == kNumTilesX * kTileWidth);
    SkASSERT(kPicHeight == kNumTilesY * kTileHeight);

    static const SkColor colors[kNumTilesX][kNumTilesY] = {
        { SK_ColorCYAN,   SK_ColorMAGENTA },
        { SK_ColorYELLOW, SK_ColorGREEN   }
    };

    for (int y = 0; y < kNumTilesY; ++y) {
        for (int x = 0; x < kNumTilesX; ++x) {
            ComposeStep& step = composeSteps->push_back();

            step.fX = SkIntToScalar(x*kTileWidth);
            step.fY = SkIntToScalar(y*kTileHeight);
            step.fPaint = SkNEW(SkPaint);
            step.fPaint->setColorFilter(
                SkColorFilter::CreateModeFilter(colors[x][y], SkXfermode::kModulate_Mode))->unref();

            step.fSurf = create_compat_surface(finalCanvas, kTileWidth, kTileHeight);

            SkCanvas* subCanvas = step.fSurf->getCanvas();

            SkMatrix trans;
            trans.setTranslate(-SkIntToScalar(x*kTileWidth), -SkIntToScalar(y*kTileHeight));

            create_content(mpd, pfGen, pictures, subCanvas, trans);
        }
    }
}

static const PFLayoutMtd gLayoutMthds[] = { simple, tiled };

namespace skiagm {
    /**
     * This GM exercises the SkMultiPictureDraw object. It tests the
     * cross product of:
     *      tiled vs. all-at-once rendering (e.g., into many or just 1 canvas)
     *      different clips (e.g., none, rect, rrect)
     *      single vs. multiple pictures (e.g., normal vs. picture-pile-style content)
     */
    class MultiPictureDraw : public GM {
    public:
        enum Content {
            kNoClipSingle_Content,
            kRectClipMulti_Content,
            kRRectClipMulti_Content,
            kPathClipMulti_Content,
            kInvPathClipMulti_Content,

            kLast_Content = kInvPathClipMulti_Content
        };

        static const int kContentCnt = kLast_Content + 1;

        enum Layout {
            kSimple_Layout,
            kTiled_Layout,

            kLast_Layout = kTiled_Layout
        };

        static const int kLayoutCnt = kLast_Layout + 1;

        MultiPictureDraw(Content content, Layout layout) : fContent(content), fLayout(layout) {
            SkASSERT(SK_ARRAY_COUNT(gLayoutMthds) == kLayoutCnt);
            SkASSERT(SK_ARRAY_COUNT(gContentMthds) == kContentCnt);

            fPictures[0] = fPictures[1] = NULL;
        }

        virtual ~MultiPictureDraw() {
            SkSafeUnref(fPictures[0]);
            SkSafeUnref(fPictures[1]);
        }

    protected:
        Content          fContent;
        Layout           fLayout;
        const SkPicture* fPictures[2];

        virtual void onOnceBeforeDraw() SK_OVERRIDE {
            fPictures[0] = make_picture(SK_ColorWHITE);
            fPictures[1] = make_picture(SK_ColorGRAY);
        }

        virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE{
            SkMultiPictureDraw mpd;
            SkTArray<ComposeStep> composeSteps;

            // Fill up the MultiPictureDraw
            (*gLayoutMthds[fLayout])(canvas, &mpd,
                                     gContentMthds[fContent],
                                     fPictures, &composeSteps);

            mpd.draw();

            // Compose all the drawn canvases into the final canvas
            for (int i = 0; i < composeSteps.count(); ++i) {
                const ComposeStep& step = composeSteps[i];

                SkAutoTUnref<SkImage> image(step.fSurf->newImageSnapshot());

                image->draw(canvas, step.fX, step.fY, step.fPaint);
            }
        }

        virtual SkISize onISize() SK_OVERRIDE{ return SkISize::Make(kPicWidth, kPicHeight); }

        virtual SkString onShortName() SK_OVERRIDE{
            static const char* gContentNames[] = {
                "noclip", "rectclip", "rrectclip", "pathclip", "invpathclip"
            };
            static const char* gLayoutNames[] = { "simple", "tiled" };

            SkASSERT(SK_ARRAY_COUNT(gLayoutNames) == kLayoutCnt);
            SkASSERT(SK_ARRAY_COUNT(gContentNames) == kContentCnt);

            SkString name("multipicturedraw_");

            name.append(gContentNames[fContent]);
            name.append("_");
            name.append(gLayoutNames[fLayout]);
            return name;
        }

        virtual uint32_t onGetFlags() const SK_OVERRIDE { return kAsBench_Flag | kSkipTiled_Flag; }

    private:
        typedef GM INHERITED;
    };

    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kNoClipSingle_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRectClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRRectClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kPathClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kInvPathClipMulti_Content,
                                                MultiPictureDraw::kSimple_Layout));)

    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kNoClipSingle_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRectClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kRRectClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kPathClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
    DEF_GM(return SkNEW_ARGS(MultiPictureDraw, (MultiPictureDraw::kInvPathClipMulti_Content,
                                                MultiPictureDraw::kTiled_Layout));)
}
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2015, Hobu Inc., hobu@hobu.co
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include "BpfWriter.hpp"

#include <pdal/pdal_internal.hpp>

#include <zlib.h>

#include <pdal/Charbuf.hpp>
#include <pdal/Options.hpp>

#include "BpfCompressor.hpp"

namespace pdal
{

Options BpfWriter::getDefaultOptions()
{
    Options ops;

    ops.add("filename", "", "Filename for BPF output");
    ops.add("compression", false, "Whether zlib compression should be used");
    ops.add("format", "dimension", "Point output format: "
        "non-interleaved(\"dimension\"), interleaved(\"point\") or "
        "byte-segregated(\"byte\")");
    ops.add("coord_id", 0, "Coordinate ID (UTM zone).");
    return ops;
}

void BpfWriter::processOptions(const Options& options)
{
    if (m_filename.empty())
        throw pdal_error("Can't write BPF file without filename.");
    bool compression = options.getValueOrDefault("compression", false);
    m_header.m_compression = compression ? BpfCompression::Zlib :
        BpfCompression::None;

    std::string fileFormat =
        options.getValueOrDefault<std::string>("format", "POINT");
    std::transform(fileFormat.begin(), fileFormat.end(), fileFormat.begin(),
        ::toupper);
    if (fileFormat.find("POINT") != std::string::npos)
        m_header.m_pointFormat = BpfFormat::PointMajor;
    else if (fileFormat.find("BYTE") != std::string::npos)
        m_header.m_pointFormat = BpfFormat::ByteMajor;
    else
        m_header.m_pointFormat = BpfFormat::DimMajor;
    if (options.hasOption("coord_id"))
    {
        m_header.m_coordType = BpfCoordType::UTM;
        m_header.m_coordId = options.getValueOrThrow<int>("coord_id");
    }
    else
    {
        m_header.m_coordType = BpfCoordType::None;
        m_header.m_coordId = 0;
    }
}

void BpfWriter::ready(PointContextRef ctx)
{
    loadBpfDimensions(ctx);
    m_stream = FileUtils::createFile(m_filename, true);
    m_header.m_version = 3;
    m_header.m_numDim = m_dims.size();
    m_header.setLog(log());

    // We will re-write the header and dimensions to account for the point
    // count and dimension min/max.
    m_header.write(m_stream);
    m_header.writeDimensions(m_stream, m_dims);
    m_header.m_len = m_stream.position();
    m_header.m_xform.m_vals[0] = m_xXform.m_scale;
    m_header.m_xform.m_vals[5] = m_yXform.m_scale;
    m_header.m_xform.m_vals[10] = m_zXform.m_scale;
}

void BpfWriter::loadBpfDimensions(PointContextRef ctx)
{
    // Verify that we have X, Y and Z and that they're the first three
    // dimensions.
    Dimension::IdList dims = ctx.dims();
    std::sort(dims.begin(), dims.end());
    if (dims.size() < 3 || dims[0] != Dimension::Id::X ||
        dims[1] != Dimension::Id::Y || dims[2] != Dimension::Id::Z)
    {
        throw pdal_error("Missing one of dimensions X, Y or Z.  "
            "Can't write BPF.");
    }

    for (auto id : dims)
    {
        BpfDimension dim;
        dim.m_id = id;
        dim.m_label = ctx.dimName(id);
        m_dims.push_back(dim);
    }
}

void BpfWriter::write(const PointBuffer& data)
{
    setAutoOffset(data);

    // We know that X, Y and Z are dimensions 0, 1 and 2.
    m_dims[0].m_offset = m_xXform.m_offset;
    m_dims[1].m_offset = m_yXform.m_offset;
    m_dims[2].m_offset = m_zXform.m_offset;

    switch (m_header.m_pointFormat)
    {
    case BpfFormat::PointMajor:
        writePointMajor(data);
        break;
    case BpfFormat::DimMajor:
        writeDimMajor(data);
        break;
    case BpfFormat::ByteMajor:
        writeByteMajor(data);
        break;
    }
    m_header.m_numPts += data.size();
}

void BpfWriter::writePointMajor(const PointBuffer& data)
{
    // Blocks of 10,000 points will ensure that we're under 16MB, even
    // for 255 dimensions.
    size_t blockpoints = std::min(10000UL, data.size());

    // For compression we're going to write to a buffer so that it can be
    // compressed before it's written to the file stream.
    BpfCompressor compressor(m_stream,
        blockpoints * sizeof(float) * m_dims.size());
    PointId idx = 0;
    while (idx < data.size())
    {
        if (m_header.m_compression)
            compressor.startBlock();
        size_t blockId;
        for (blockId = 0; idx < data.size() && blockId < blockpoints;
            ++idx, ++blockId)
        {
            for (auto & bpfDim : m_dims)
            {
                double d = getAdjustedValue(data, bpfDim, idx);
                m_stream << (float)d;
            }
        }
        if (m_header.m_compression)
        {
            compressor.compress();
            compressor.finish();
        }
    }
}

void BpfWriter::writeDimMajor(const PointBuffer& data)
{
    // We're going to pretend for now that we only even have one point buffer.
    BpfCompressor compressor(m_stream, data.size() * sizeof(float));

    for (auto & bpfDim : m_dims)
    {

        if (m_header.m_compression)
            compressor.startBlock();
        for (PointId idx = 0; idx < data.size(); ++idx)
        {
            double d = getAdjustedValue(data, bpfDim, idx);
            m_stream << (float)d;
        }
        if (m_header.m_compression)
        {
            compressor.compress();
            compressor.finish();
        }
    }
}

void BpfWriter::writeByteMajor(const PointBuffer& data)
{
    union
    {
        float f;
        uint32_t u32;
    } uu;

    // We're going to pretend for now that we only even have one point buffer.

    BpfCompressor compressor(m_stream,
        data.size() * sizeof(float) * m_dims.size());

    if (m_header.m_compression)
        compressor.startBlock();
    for (auto & bpfDim : m_dims)
    {
        for (size_t b = 0; b < sizeof(float); b++)
        {
            for (PointId idx = 0; idx < data.size(); ++idx)
            {
                uu.f = (float)getAdjustedValue(data, bpfDim, idx);
                uint8_t u8 = (uint8_t)(uu.u32 >> (b * CHAR_BIT));
                m_stream << u8;
            }
        }
    }
    if (m_header.m_compression)
    {
        compressor.compress();
        compressor.finish();
    }
}

double BpfWriter::getAdjustedValue(const PointBuffer& buf,
    BpfDimension& bpfDim, PointId idx)
{
    double d = buf.getFieldAs<double>(bpfDim.m_id, idx);
    bpfDim.m_min = std::min(bpfDim.m_min, d);
    bpfDim.m_max = std::max(bpfDim.m_max, d);

    if (bpfDim.m_id == Dimension::Id::X)
        d /= m_xXform.m_scale;
    else if (bpfDim.m_id == Dimension::Id::Y)
        d /= m_yXform.m_scale;
    else if (bpfDim.m_id == Dimension::Id::Z)
        d /= m_zXform.m_scale;
    d -= bpfDim.m_offset;
    return (d - bpfDim.m_offset);
}

void BpfWriter::done(PointContextRef)
{
    // Rewrite the header to update the the correct number of points and
    // statistics.
    m_stream.seek(0);
    m_header.write(m_stream);
    m_header.writeDimensions(m_stream, m_dims);
    m_stream.flush();
}

} //namespace pdal
<commit_msg>Fix duplicate backout of offset.<commit_after>/******************************************************************************
* Copyright (c) 2015, Hobu Inc., hobu@hobu.co
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include "BpfWriter.hpp"

#include <pdal/pdal_internal.hpp>

#include <zlib.h>

#include <pdal/Charbuf.hpp>
#include <pdal/Options.hpp>

#include "BpfCompressor.hpp"

namespace pdal
{

Options BpfWriter::getDefaultOptions()
{
    Options ops;

    ops.add("filename", "", "Filename for BPF output");
    ops.add("compression", false, "Whether zlib compression should be used");
    ops.add("format", "dimension", "Point output format: "
        "non-interleaved(\"dimension\"), interleaved(\"point\") or "
        "byte-segregated(\"byte\")");
    ops.add("coord_id", 0, "Coordinate ID (UTM zone).");
    return ops;
}

void BpfWriter::processOptions(const Options& options)
{
    if (m_filename.empty())
        throw pdal_error("Can't write BPF file without filename.");
    bool compression = options.getValueOrDefault("compression", false);
    m_header.m_compression = compression ? BpfCompression::Zlib :
        BpfCompression::None;

    std::string fileFormat =
        options.getValueOrDefault<std::string>("format", "POINT");
    std::transform(fileFormat.begin(), fileFormat.end(), fileFormat.begin(),
        ::toupper);
    if (fileFormat.find("POINT") != std::string::npos)
        m_header.m_pointFormat = BpfFormat::PointMajor;
    else if (fileFormat.find("BYTE") != std::string::npos)
        m_header.m_pointFormat = BpfFormat::ByteMajor;
    else
        m_header.m_pointFormat = BpfFormat::DimMajor;
    if (options.hasOption("coord_id"))
    {
        m_header.m_coordType = BpfCoordType::UTM;
        m_header.m_coordId = options.getValueOrThrow<int>("coord_id");
    }
    else
    {
        m_header.m_coordType = BpfCoordType::None;
        m_header.m_coordId = 0;
    }
}

void BpfWriter::ready(PointContextRef ctx)
{
    loadBpfDimensions(ctx);
    m_stream = FileUtils::createFile(m_filename, true);
    m_header.m_version = 3;
    m_header.m_numDim = m_dims.size();
    m_header.setLog(log());

    // We will re-write the header and dimensions to account for the point
    // count and dimension min/max.
    m_header.write(m_stream);
    m_header.writeDimensions(m_stream, m_dims);
    m_header.m_len = m_stream.position();
    m_header.m_xform.m_vals[0] = m_xXform.m_scale;
    m_header.m_xform.m_vals[5] = m_yXform.m_scale;
    m_header.m_xform.m_vals[10] = m_zXform.m_scale;
}

void BpfWriter::loadBpfDimensions(PointContextRef ctx)
{
    // Verify that we have X, Y and Z and that they're the first three
    // dimensions.
    Dimension::IdList dims = ctx.dims();
    std::sort(dims.begin(), dims.end());
    if (dims.size() < 3 || dims[0] != Dimension::Id::X ||
        dims[1] != Dimension::Id::Y || dims[2] != Dimension::Id::Z)
    {
        throw pdal_error("Missing one of dimensions X, Y or Z.  "
            "Can't write BPF.");
    }

    for (auto id : dims)
    {
        BpfDimension dim;
        dim.m_id = id;
        dim.m_label = ctx.dimName(id);
        m_dims.push_back(dim);
    }
}

void BpfWriter::write(const PointBuffer& data)
{
    setAutoOffset(data);

    // We know that X, Y and Z are dimensions 0, 1 and 2.
    m_dims[0].m_offset = m_xXform.m_offset;
    m_dims[1].m_offset = m_yXform.m_offset;
    m_dims[2].m_offset = m_zXform.m_offset;

    switch (m_header.m_pointFormat)
    {
    case BpfFormat::PointMajor:
        writePointMajor(data);
        break;
    case BpfFormat::DimMajor:
        writeDimMajor(data);
        break;
    case BpfFormat::ByteMajor:
        writeByteMajor(data);
        break;
    }
    m_header.m_numPts += data.size();
}

void BpfWriter::writePointMajor(const PointBuffer& data)
{
    // Blocks of 10,000 points will ensure that we're under 16MB, even
    // for 255 dimensions.
    size_t blockpoints = std::min(10000UL, data.size());

    // For compression we're going to write to a buffer so that it can be
    // compressed before it's written to the file stream.
    BpfCompressor compressor(m_stream,
        blockpoints * sizeof(float) * m_dims.size());
    PointId idx = 0;
    while (idx < data.size())
    {
        if (m_header.m_compression)
            compressor.startBlock();
        size_t blockId;
        for (blockId = 0; idx < data.size() && blockId < blockpoints;
            ++idx, ++blockId)
        {
            for (auto & bpfDim : m_dims)
            {
                double d = getAdjustedValue(data, bpfDim, idx);
                m_stream << (float)d;
            }
        }
        if (m_header.m_compression)
        {
            compressor.compress();
            compressor.finish();
        }
    }
}

void BpfWriter::writeDimMajor(const PointBuffer& data)
{
    // We're going to pretend for now that we only even have one point buffer.
    BpfCompressor compressor(m_stream, data.size() * sizeof(float));

    for (auto & bpfDim : m_dims)
    {

        if (m_header.m_compression)
            compressor.startBlock();
        for (PointId idx = 0; idx < data.size(); ++idx)
        {
            double d = getAdjustedValue(data, bpfDim, idx);
            m_stream << (float)d;
        }
        if (m_header.m_compression)
        {
            compressor.compress();
            compressor.finish();
        }
    }
}

void BpfWriter::writeByteMajor(const PointBuffer& data)
{
    union
    {
        float f;
        uint32_t u32;
    } uu;

    // We're going to pretend for now that we only even have one point buffer.

    BpfCompressor compressor(m_stream,
        data.size() * sizeof(float) * m_dims.size());

    if (m_header.m_compression)
        compressor.startBlock();
    for (auto & bpfDim : m_dims)
    {
        for (size_t b = 0; b < sizeof(float); b++)
        {
            for (PointId idx = 0; idx < data.size(); ++idx)
            {
                uu.f = (float)getAdjustedValue(data, bpfDim, idx);
                uint8_t u8 = (uint8_t)(uu.u32 >> (b * CHAR_BIT));
                m_stream << u8;
            }
        }
    }
    if (m_header.m_compression)
    {
        compressor.compress();
        compressor.finish();
    }
}

double BpfWriter::getAdjustedValue(const PointBuffer& buf,
    BpfDimension& bpfDim, PointId idx)
{
    double d = buf.getFieldAs<double>(bpfDim.m_id, idx);
    bpfDim.m_min = std::min(bpfDim.m_min, d);
    bpfDim.m_max = std::max(bpfDim.m_max, d);

    if (bpfDim.m_id == Dimension::Id::X)
        d /= m_xXform.m_scale;
    else if (bpfDim.m_id == Dimension::Id::Y)
        d /= m_yXform.m_scale;
    else if (bpfDim.m_id == Dimension::Id::Z)
        d /= m_zXform.m_scale;
    return (d - bpfDim.m_offset);
}

void BpfWriter::done(PointContextRef)
{
    // Rewrite the header to update the the correct number of points and
    // statistics.
    m_stream.seek(0);
    m_header.write(m_stream);
    m_header.writeDimensions(m_stream, m_dims);
    m_stream.flush();
}

} //namespace pdal
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#pragma once

#include <pdal/Compression.hpp>
#include <pdal/FlexWriter.hpp>

#include "HeaderVal.hpp"
#include "LasError.hpp"
#include "LasHeader.hpp"
#include "LasUtils.hpp"
#include "SummaryData.hpp"
#include "ZipPoint.hpp"

extern "C" int32_t LasWriter_ExitFunc();
extern "C" PF_ExitFunc LasWriter_InitPlugin();

namespace pdal
{
class LasTester;
class NitfWriter;
class GeotiffSupport;

struct VlrOptionInfo
{
    std::string m_name;
    std::string m_value;
    std::string m_userId;
    uint16_t m_recordId;
    std::string m_description;
};

class PDAL_DLL LasWriter : public FlexWriter
{
    friend class LasTester;
    friend class NitfWriter;
public:
    static void * create();
    static int32_t destroy(void *);
    std::string getName() const;

    LasWriter();

    Options getDefaultOptions();

protected:
    void prepOutput(std::ostream *out, const SpatialReference& srs);
    void finishOutput();

private:
    LasError m_error;
    LasHeader m_lasHeader;
    std::unique_ptr<SummaryData> m_summaryData;
    std::unique_ptr<LASzipper> m_zipper;
    std::unique_ptr<ZipPoint> m_zipPoint;
    std::unique_ptr<LazPerfVlrCompressor> m_compressor;
    bool m_discardHighReturnNumbers;
    std::map<std::string, std::string> m_headerVals;
    std::vector<VlrOptionInfo> m_optionInfos;
    std::ostream *m_ostream;
    std::vector<VariableLengthRecord> m_vlrs;
    std::vector<ExtVariableLengthRecord> m_eVlrs;
    std::vector<ExtraDim> m_extraDims;
    uint16_t m_extraByteLen;
    SpatialReference m_srs;
    std::string m_curFilename;
    std::set<std::string> m_forwards;
    bool m_forwardVlrs;
    LasCompression::Enum m_compression;

    NumHeaderVal<uint8_t, 1, 1> m_majorVersion;
    NumHeaderVal<uint8_t, 1, 4> m_minorVersion;
    NumHeaderVal<uint8_t, 0, 10> m_dataformatId;
    // MSVC doesn't see numeric_limits::max() as constexpr do doesn't allow
    // it as defaults for templates.  Remove when possible.
    NumHeaderVal<uint16_t, 0, 65535> m_filesourceId;
    NumHeaderVal<uint16_t, 0, 15> m_globalEncoding;
    UuidHeaderVal m_projectId;
    StringHeaderVal<32> m_systemId;
    StringHeaderVal<32> m_softwareId;
    NumHeaderVal<uint16_t, 0, 366> m_creationDoy;
    // MSVC doesn't see numeric_limits::max() as constexpr do doesn't allow
    // them as defaults for templates.  Remove when possible.
    NumHeaderVal<uint16_t, 0, 65535> m_creationYear;
    StringHeaderVal<20> m_scaleX;
    StringHeaderVal<20> m_scaleY;
    StringHeaderVal<20> m_scaleZ;
    StringHeaderVal<20> m_offsetX;
    StringHeaderVal<20> m_offsetY;
    StringHeaderVal<20> m_offsetZ;
    MetadataNode m_forwardMetadata;

    virtual void processOptions(const Options& options);
    virtual void prepared(PointTableRef table);
    virtual void readyTable(PointTableRef table);
    virtual void readyFile(const std::string& filename,
        const SpatialReference& srs);
    virtual void writeView(const PointViewPtr view);
    virtual void doneFile();

    void fillForwardList(const Options& options);
    void getHeaderOptions(const Options& options);
    template <typename T>
    void handleHeaderForward(const std::string& s, T& headerVal,
        const MetadataNode& base);
    void handleHeaderForwards(MetadataNode& forward);
    void fillHeader();
    point_count_t fillWriteBuf(const PointView& view, PointId startId,
        std::vector<char>& buf);
    void writeLasZipBuf(char *data, size_t pointLen, point_count_t numPts);
    void writeLazPerfBuf(char *data, size_t pointLen, point_count_t numPts);
    void setVlrsFromMetadata(MetadataNode& forward);
    MetadataNode findVlrMetadata(MetadataNode node, uint16_t recordId,
        const std::string& userId);
    void setExtraBytesVlr();
    void setVlrsFromSpatialRef();
    void readyCompression();
    void readyLasZipCompression();
    void readyLazPerfCompression();
    void openCompression();
    void addVlr(const std::string& userId, uint16_t recordId,
        const std::string& description, std::vector<uint8_t>& data);
    void deleteVlr(const std::string& userId, uint16_t recordId);
    void addGeotiffVlrs();
    void addGeotiffVlr(GeotiffSupport& geotiff, uint16_t recordId,
        const std::string& description);
    bool addWktVlr();
    void finishLasZipOutput();
    void finishLazPerfOutput();

    LasWriter& operator=(const LasWriter&); // not implemented
    LasWriter(const LasWriter&); // not implemented
};

} // namespace pdal
<commit_msg>Valid global_encoding values can go up to 31. Close #1064<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#pragma once

#include <pdal/Compression.hpp>
#include <pdal/FlexWriter.hpp>

#include "HeaderVal.hpp"
#include "LasError.hpp"
#include "LasHeader.hpp"
#include "LasUtils.hpp"
#include "SummaryData.hpp"
#include "ZipPoint.hpp"

extern "C" int32_t LasWriter_ExitFunc();
extern "C" PF_ExitFunc LasWriter_InitPlugin();

namespace pdal
{
class LasTester;
class NitfWriter;
class GeotiffSupport;

struct VlrOptionInfo
{
    std::string m_name;
    std::string m_value;
    std::string m_userId;
    uint16_t m_recordId;
    std::string m_description;
};

class PDAL_DLL LasWriter : public FlexWriter
{
    friend class LasTester;
    friend class NitfWriter;
public:
    static void * create();
    static int32_t destroy(void *);
    std::string getName() const;

    LasWriter();

    Options getDefaultOptions();

protected:
    void prepOutput(std::ostream *out, const SpatialReference& srs);
    void finishOutput();

private:
    LasError m_error;
    LasHeader m_lasHeader;
    std::unique_ptr<SummaryData> m_summaryData;
    std::unique_ptr<LASzipper> m_zipper;
    std::unique_ptr<ZipPoint> m_zipPoint;
    std::unique_ptr<LazPerfVlrCompressor> m_compressor;
    bool m_discardHighReturnNumbers;
    std::map<std::string, std::string> m_headerVals;
    std::vector<VlrOptionInfo> m_optionInfos;
    std::ostream *m_ostream;
    std::vector<VariableLengthRecord> m_vlrs;
    std::vector<ExtVariableLengthRecord> m_eVlrs;
    std::vector<ExtraDim> m_extraDims;
    uint16_t m_extraByteLen;
    SpatialReference m_srs;
    std::string m_curFilename;
    std::set<std::string> m_forwards;
    bool m_forwardVlrs;
    LasCompression::Enum m_compression;

    NumHeaderVal<uint8_t, 1, 1> m_majorVersion;
    NumHeaderVal<uint8_t, 1, 4> m_minorVersion;
    NumHeaderVal<uint8_t, 0, 10> m_dataformatId;
    // MSVC doesn't see numeric_limits::max() as constexpr do doesn't allow
    // it as defaults for templates.  Remove when possible.
    NumHeaderVal<uint16_t, 0, 65535> m_filesourceId;
    NumHeaderVal<uint16_t, 0, 31> m_globalEncoding;
    UuidHeaderVal m_projectId;
    StringHeaderVal<32> m_systemId;
    StringHeaderVal<32> m_softwareId;
    NumHeaderVal<uint16_t, 0, 366> m_creationDoy;
    // MSVC doesn't see numeric_limits::max() as constexpr do doesn't allow
    // them as defaults for templates.  Remove when possible.
    NumHeaderVal<uint16_t, 0, 65535> m_creationYear;
    StringHeaderVal<20> m_scaleX;
    StringHeaderVal<20> m_scaleY;
    StringHeaderVal<20> m_scaleZ;
    StringHeaderVal<20> m_offsetX;
    StringHeaderVal<20> m_offsetY;
    StringHeaderVal<20> m_offsetZ;
    MetadataNode m_forwardMetadata;

    virtual void processOptions(const Options& options);
    virtual void prepared(PointTableRef table);
    virtual void readyTable(PointTableRef table);
    virtual void readyFile(const std::string& filename,
        const SpatialReference& srs);
    virtual void writeView(const PointViewPtr view);
    virtual void doneFile();

    void fillForwardList(const Options& options);
    void getHeaderOptions(const Options& options);
    template <typename T>
    void handleHeaderForward(const std::string& s, T& headerVal,
        const MetadataNode& base);
    void handleHeaderForwards(MetadataNode& forward);
    void fillHeader();
    point_count_t fillWriteBuf(const PointView& view, PointId startId,
        std::vector<char>& buf);
    void writeLasZipBuf(char *data, size_t pointLen, point_count_t numPts);
    void writeLazPerfBuf(char *data, size_t pointLen, point_count_t numPts);
    void setVlrsFromMetadata(MetadataNode& forward);
    MetadataNode findVlrMetadata(MetadataNode node, uint16_t recordId,
        const std::string& userId);
    void setExtraBytesVlr();
    void setVlrsFromSpatialRef();
    void readyCompression();
    void readyLasZipCompression();
    void readyLazPerfCompression();
    void openCompression();
    void addVlr(const std::string& userId, uint16_t recordId,
        const std::string& description, std::vector<uint8_t>& data);
    void deleteVlr(const std::string& userId, uint16_t recordId);
    void addGeotiffVlrs();
    void addGeotiffVlr(GeotiffSupport& geotiff, uint16_t recordId,
        const std::string& description);
    bool addWktVlr();
    void finishLasZipOutput();
    void finishLazPerfOutput();

    LasWriter& operator=(const LasWriter&); // not implemented
    LasWriter(const LasWriter&); // not implemented
};

} // namespace pdal
<|endoftext|>


<commit_before>#include <taichi/lang.h>
#include <taichi/util.h>
#include <taichi/visual/gui.h>
#include <taichi/system/profiler.h>
#include <taichi/visualization/particle_visualization.h>

TC_NAMESPACE_BEGIN

using namespace Tlang;

constexpr int n = 256;

constexpr int num_ch1 = 16, num_ch2 = 16;

auto cnn = [](std::vector<std::string> cli_param) {
  CoreState::set_trigger_gdb_when_crash(true);
  auto param = parse_param(cli_param);
  auto gpu = param.get("gpu", true);
  auto opt = param.get("opt", true);
  auto use_dense = param.get("use_dense", false);
  auto write_input_voxel = param.get("write_input", true);
  TC_P(use_dense);

  Program prog(gpu ? Arch::gpu : Arch::x86_64);
  prog.config.simplify_before_lower_access = opt;
  prog.config.lower_access = opt;
  prog.config.simplify_after_lower_access = opt;
  // prog.config.print_ir = true;

  // constexpr int dim = 3;

  int block_size = gpu ? 4 : 8;

  Global(layer1, f32);
  Global(layer2, f32);
  Global(weights, f32);

  layout([&]() {
    auto ijkl = Indices(0, 1, 2, 3);
    if (use_dense) {
      root.dense(ijkl, {n, n, n, num_ch1}).place(layer1);
      root.dense(ijkl, {n, n, n, num_ch2}).place(layer2);
    } else {
      root.dense(ijkl, {n / block_size, n / block_size, n / block_size, 1})
          .bitmasked()
          .dense(ijkl, {block_size, block_size, block_size, num_ch1})
          .place(layer1);
      root.dense(ijkl, {n / block_size, n / block_size, n / block_size, 1})
          .bitmasked()
          .dense(ijkl, {block_size, block_size, block_size, num_ch2})
          .place(layer2);
    }
    root.dense(ijkl, {4, 4, 4, num_ch1 * num_ch2}).place(weights);
  });

  auto tex = create_instance<Texture>(
      "mesh", Dict()
                  .set("resolution", Vector3(n))
                  .set("translate", Vector3(0.55, 0.35, 0.47))
                  .set("scale", Vector3(0.5))
                  .set("adaptive", false)
                  .set("filename", "$mpm/bunny_small.obj"));
  float *in_data = new float[num_ch1 * n * n * n];
  memset(in_data, 0, sizeof(float) * num_ch1 * n * n * n);
  int count = 0;
  for (int i = 1; i < n - 2; i++) {
    for (int j = 1; j < n - 2; j++) {
      for (int k = 1; k < n - 2; k++) {
        bool inside = tex->sample((Vector3(0.5f) + Vector3(i, j, k)) *
                                  Vector3(1.0f / (n - 1)))
                          .x > 0.5f;
        // inside = pow<2>(i - n / 2) + pow<2>(k - n / 2) < pow<2>(n / 2) / 2;
        // inside = i < n * 0.8 && j < n * 0.8 && k < n * 0.8;
        if (inside) {
          for (int c = 0; c < num_ch1; c++) {
            in_data[c * n * n * n + k * n * n + j * n + i] = 1.f;
            layer1.val<float32>(i, j, k, c) = 1.f;
            count++;
          }
        }
      }
    }
  }
  std::cout << "non_zero:" << count << ", total:" << (num_ch1 * n * n * n)
            << std::endl;
  if (write_input_voxel) {
    auto f = fopen("bunny_sparse.bin", "wb");
    fwrite(in_data, sizeof(float), num_ch1 * n * n * n, f);
    fclose(f);
  }

  Kernel(forward).def([&] {
    // Cache(0, layer1);
    bool use_cache = false;
    if (opt && gpu) {
      use_cache = true;
      CacheL1(weights);
    }
    if (!gpu) {
      Parallelize(8);
      Vectorize(block_size);
    } else {
      BlockDim(256);
    }
    For(layer2, [&](Expr i, Expr j, Expr k, Expr c_out) {
      auto sum = Var(0.0f);
      for (int c_in = 0; c_in < num_ch1; c_in++) {
        for (int dx = -1; dx < 2; dx++) {
          for (int dy = -1; dy < 2; dy++) {
            for (int dz = -1; dz < 2; dz++) {
              auto weight = weights[Expr(dx + 1), Expr(dy + 1), Expr(dz + 1),
                                    c_in * num_ch2 + c_out];
              auto c_in2 = use_cache ? AssumeInRange(c_in, c_out, 0, 1) : c_in;
              sum += weight * layer1[i + dx, j + dy, k + dz, c_in2];
              // layer2[i, j, k, c_out] += weight * layer1[i + dx, j + dy, k +
              // dz, c_in];
            }
          }
        }
      }
      layer2[i, j, k, c_out] = sum;
    });
  });

  // expand blocks
  kernel([&] {
    if (!gpu) {
      Parallelize(8);
      // Vectorize(block_size);
    } else {
      BlockDim(256);
    }

    kernel_name("dilate");
    For(layer1, [&](Expr i, Expr j, Expr k) {
      If(i % block_size == 0 && j % block_size == 0 && k % block_size == 0)
          .Then([&] {
            for (int x = -1; x < 2; x++) {
              for (int y = -1; y < 2; y++) {
                for (int z = -1; z < 2; z++) {
                  layer2[i + x * block_size, j + y * block_size,
                         k + z * block_size, 0] =
                      0.0f;  // simply activate the block
                }
              }
            }
          });
    });
  })();

  for (int c_out = 0; c_out < num_ch2; c_out++) {
    for (int c_in = 0; c_in < num_ch1; c_in++) {
      float inc = 0.1f;
      for (int dx = -1; dx < 2; dx++) {
        for (int dy = -1; dy < 2; dy++) {
          for (int dz = -1; dz < 2; dz++) {
            if (dx == 0 && dy == 0 && dz == 0)
              weights.val<float32>(dx + 1, dy + 1, dz + 1,
                                   c_in * num_ch2 + c_out) = inc;
            inc += 0.1f;
          }
        }
      }
    }
  }

  // prog.config.print_ir = true;
  for (int i = 0; i < 50; i++) {
    forward();
  }
  prog.profiler_print();

  // Write the first layer of output
  float *data = new float[(n - 2) * (n - 2) * (n - 2)];
  int non_zero = 0;
  int zero = 0;
  for (int i = 1; i < (n - 1); i++) {
    for (int j = 1; j < (n - 1); j++) {
      for (int k = 1; k < (n - 1); k++) {
        data[((0 * (n - 2) + (k - 1)) * (n - 2) + (j - 1)) * (n - 2) +
             (i - 1)] = layer2.val<float32>(i, j, k, 0);
        if (layer2.val<float32>(i, j, k, 0) != 0) {
          non_zero++;
        } else {
          zero++;
        }
      }
    }
  }
  std::cout << "Non zero:" << non_zero << ", zero:" << zero << std::endl;
  std::cerr << "Sparsity:" << (double)non_zero / (double)(non_zero + zero)
            << std::endl;
  auto f_out = fopen("our_bunny.bin", "wb");
  fwrite(data, sizeof(float), (n - 2) * (n - 2) * (n - 2), f_out);
  fclose(f_out);

#if 0
  int gui_res = 512;
  GUI gui("Sparse CNN", Vector2i(gui_res + 200, gui_res), false);
  int layer = 1;
  int k = 0;
  int channel = 0;
  gui.slider("z", k, 0, n - 1)
      .slider("Layer", layer, 1, 2)
      .slider("Channel", channel, 0, num_ch1);

  int scale = gui_res / n;
  auto &canvas = gui.get_canvas();
  for (int frame = 1;; frame++) {
    for (int i = 0; i < gui_res - scale; i++) {
      for (int j = 0; j < gui_res - scale; j++) {
        real dx;
        if (layer == 1) {
          dx = layer1.val<float32>(i / scale, j / scale, k, channel);
        } else {
          dx = layer2.val<float32>(i / scale, j / scale, k, channel);
        }
        canvas.img[i][j] = Vector4(0.5f) + Vector4(dx) * 0.5f;
      }
    }
    gui.update();
  }
#endif
};
TC_REGISTER_TASK(cnn);

TC_NAMESPACE_END
<commit_msg>explicit cache_l1 hint for cnn<commit_after>#include <taichi/lang.h>
#include <taichi/util.h>
#include <taichi/visual/gui.h>
#include <taichi/system/profiler.h>
#include <taichi/visualization/particle_visualization.h>

TC_NAMESPACE_BEGIN

using namespace Tlang;

constexpr int n = 256;

constexpr int num_ch1 = 16, num_ch2 = 16;

auto cnn = [](std::vector<std::string> cli_param) {
  CoreState::set_trigger_gdb_when_crash(true);
  auto param = parse_param(cli_param);
  auto gpu = param.get("gpu", true);
  auto opt = param.get("opt", true);
  auto cache_l1 = param.get("cache_l1", true);
  auto use_dense = param.get("use_dense", false);
  auto write_input_voxel = param.get("write_input", true);
  TC_P(use_dense);

  Program prog(gpu ? Arch::gpu : Arch::x86_64);
  prog.config.simplify_before_lower_access = opt;
  prog.config.lower_access = opt;
  prog.config.simplify_after_lower_access = opt;
  // prog.config.print_ir = true;

  // constexpr int dim = 3;

  int block_size = gpu ? 4 : 8;

  Global(layer1, f32);
  Global(layer2, f32);
  Global(weights, f32);

  layout([&]() {
    auto ijkl = Indices(0, 1, 2, 3);
    if (use_dense) {
      root.dense(ijkl, {n, n, n, num_ch1}).place(layer1);
      root.dense(ijkl, {n, n, n, num_ch2}).place(layer2);
    } else {
      root.dense(ijkl, {n / block_size, n / block_size, n / block_size, 1})
          .bitmasked()
          .dense(ijkl, {block_size, block_size, block_size, num_ch1})
          .place(layer1);
      root.dense(ijkl, {n / block_size, n / block_size, n / block_size, 1})
          .bitmasked()
          .dense(ijkl, {block_size, block_size, block_size, num_ch2})
          .place(layer2);
    }
    root.dense(ijkl, {4, 4, 4, num_ch1 * num_ch2}).place(weights);
  });

  auto tex = create_instance<Texture>(
      "mesh", Dict()
                  .set("resolution", Vector3(n))
                  .set("translate", Vector3(0.55, 0.35, 0.47))
                  .set("scale", Vector3(0.5))
                  .set("adaptive", false)
                  .set("filename", "$mpm/bunny_small.obj"));
  float *in_data = new float[num_ch1 * n * n * n];
  memset(in_data, 0, sizeof(float) * num_ch1 * n * n * n);
  int count = 0;
  for (int i = 1; i < n - 2; i++) {
    for (int j = 1; j < n - 2; j++) {
      for (int k = 1; k < n - 2; k++) {
        bool inside = tex->sample((Vector3(0.5f) + Vector3(i, j, k)) *
                                  Vector3(1.0f / (n - 1)))
                          .x > 0.5f;
        // inside = pow<2>(i - n / 2) + pow<2>(k - n / 2) < pow<2>(n / 2) / 2;
        // inside = i < n * 0.8 && j < n * 0.8 && k < n * 0.8;
        if (inside) {
          for (int c = 0; c < num_ch1; c++) {
            in_data[c * n * n * n + k * n * n + j * n + i] = 1.f;
            layer1.val<float32>(i, j, k, c) = 1.f;
            count++;
          }
        }
      }
    }
  }
  std::cout << "non_zero:" << count << ", total:" << (num_ch1 * n * n * n)
            << std::endl;
  if (write_input_voxel) {
    auto f = fopen("bunny_sparse.bin", "wb");
    fwrite(in_data, sizeof(float), num_ch1 * n * n * n, f);
    fclose(f);
  }

  Kernel(forward).def([&] {
    bool use_cache = false;
    if (opt && gpu) {
      use_cache = true;
      if (cache_l1)
        CacheL1(weights);
    }
    if (!gpu) {
      Parallelize(8);
      Vectorize(block_size);
    } else {
      BlockDim(256);
    }
    For(layer2, [&](Expr i, Expr j, Expr k, Expr c_out) {
      auto sum = Var(0.0f);
      for (int c_in = 0; c_in < num_ch1; c_in++) {
        for (int dx = -1; dx < 2; dx++) {
          for (int dy = -1; dy < 2; dy++) {
            for (int dz = -1; dz < 2; dz++) {
              auto weight = weights[Expr(dx + 1), Expr(dy + 1), Expr(dz + 1),
                                    c_in * num_ch2 + c_out];
              auto c_in2 = use_cache ? AssumeInRange(c_in, c_out, 0, 1) : c_in;
              sum += weight * layer1[i + dx, j + dy, k + dz, c_in2];
              // layer2[i, j, k, c_out] += weight * layer1[i + dx, j + dy, k +
              // dz, c_in];
            }
          }
        }
      }
      layer2[i, j, k, c_out] = sum;
    });
  });

  // expand blocks
  kernel([&] {
    if (!gpu) {
      Parallelize(8);
      // Vectorize(block_size);
    } else {
      BlockDim(256);
    }

    kernel_name("dilate");
    For(layer1, [&](Expr i, Expr j, Expr k) {
      If(i % block_size == 0 && j % block_size == 0 && k % block_size == 0)
          .Then([&] {
            for (int x = -1; x < 2; x++) {
              for (int y = -1; y < 2; y++) {
                for (int z = -1; z < 2; z++) {
                  layer2[i + x * block_size, j + y * block_size,
                         k + z * block_size, 0] =
                      0.0f;  // simply activate the block
                }
              }
            }
          });
    });
  })();

  for (int c_out = 0; c_out < num_ch2; c_out++) {
    for (int c_in = 0; c_in < num_ch1; c_in++) {
      float inc = 0.1f;
      for (int dx = -1; dx < 2; dx++) {
        for (int dy = -1; dy < 2; dy++) {
          for (int dz = -1; dz < 2; dz++) {
            if (dx == 0 && dy == 0 && dz == 0)
              weights.val<float32>(dx + 1, dy + 1, dz + 1,
                                   c_in * num_ch2 + c_out) = inc;
            inc += 0.1f;
          }
        }
      }
    }
  }

  // prog.config.print_ir = true;
  for (int i = 0; i < 50; i++) {
    forward();
  }
  prog.profiler_print();

  // Write the first layer of output
  float *data = new float[(n - 2) * (n - 2) * (n - 2)];
  int non_zero = 0;
  int zero = 0;
  for (int i = 1; i < (n - 1); i++) {
    for (int j = 1; j < (n - 1); j++) {
      for (int k = 1; k < (n - 1); k++) {
        data[((0 * (n - 2) + (k - 1)) * (n - 2) + (j - 1)) * (n - 2) +
             (i - 1)] = layer2.val<float32>(i, j, k, 0);
        if (layer2.val<float32>(i, j, k, 0) != 0) {
          non_zero++;
        } else {
          zero++;
        }
      }
    }
  }
  std::cout << "Non zero:" << non_zero << ", zero:" << zero << std::endl;
  std::cerr << "Sparsity:" << (double)non_zero / (double)(non_zero + zero)
            << std::endl;
  auto f_out = fopen("our_bunny.bin", "wb");
  fwrite(data, sizeof(float), (n - 2) * (n - 2) * (n - 2), f_out);
  fclose(f_out);

#if 0
  int gui_res = 512;
  GUI gui("Sparse CNN", Vector2i(gui_res + 200, gui_res), false);
  int layer = 1;
  int k = 0;
  int channel = 0;
  gui.slider("z", k, 0, n - 1)
      .slider("Layer", layer, 1, 2)
      .slider("Channel", channel, 0, num_ch1);

  int scale = gui_res / n;
  auto &canvas = gui.get_canvas();
  for (int frame = 1;; frame++) {
    for (int i = 0; i < gui_res - scale; i++) {
      for (int j = 0; j < gui_res - scale; j++) {
        real dx;
        if (layer == 1) {
          dx = layer1.val<float32>(i / scale, j / scale, k, channel);
        } else {
          dx = layer2.val<float32>(i / scale, j / scale, k, channel);
        }
        canvas.img[i][j] = Vector4(0.5f) + Vector4(dx) * 0.5f;
      }
    }
    gui.update();
  }
#endif
};
TC_REGISTER_TASK(cnn);

TC_NAMESPACE_END
<|endoftext|>


<commit_before>/* bzflag
* Copyright (c) 1993 - 2008 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <stdio.h>
#include <stdarg.h>
#include <sstream>
#include "plugin_files.h"
#include "plugin_utils.h"

#ifdef _WIN32
#define _DirDelim '\\'

#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <io.h>
#include <direct.h>

bool WindowsAddFileStack ( const char *szPathName, const char* fileMask, bool bRecursive,std::vector<std::string> &list, bool justDirs = false )
{
  struct _finddata_t fileInfo;

  long		hFile;
  std::string searchstr;

  std::string FilePath;

  bool	bDone = false;

  searchstr = szPathName;
  searchstr += "\\";
  if (bRecursive)
    searchstr += "*.*";
  else if (fileMask)
    searchstr += fileMask;
  else
    searchstr += "*.*";

  std::string extenstionSearch;

  if ( fileMask && strchr(fileMask,'.'))
    extenstionSearch = strchr(fileMask,'.')+1;

  hFile = (long)_findfirst(searchstr.c_str(),&fileInfo);

  if (hFile != -1)
  {
    while (!bDone)
    {
      if ((strlen(fileInfo.name) >0) && (strcmp(fileInfo.name,".") != 0) &&
	(strcmp(fileInfo.name,"..") != 0))
      {
	FilePath = szPathName;
	//if (!(fileInfo.attrib & _A_SUBDIR ))
	  FilePath += "\\";
	FilePath += fileInfo.name;

	if (justDirs && (fileInfo.attrib & _A_SUBDIR ))	// we neever do just dirs recrusively
	  list.push_back(FilePath);
	else if (!justDirs)
	{
	  if ( (fileInfo.attrib & _A_SUBDIR ) && bRecursive)
	    WindowsAddFileStack(FilePath.c_str(),fileMask,bRecursive,list);
	  else if (!(fileInfo.attrib & _A_SUBDIR) )
	  {
	    if (bRecursive && fileMask)	// if we are recusive we need to check extension manualy, so we get dirs and stuf
	    {
	      if (strrchr(FilePath.c_str(),'.'))
	      {
		if ( stricmp(strrchr(FilePath.c_str(),'.')+1, extenstionSearch.c_str() ) == 0 )
		  list.push_back(FilePath);
	      }
	    }
	    else
	      list.push_back(FilePath);
	  }
	}
      }
      if (_findnext(hFile,&fileInfo) == -1)
	bDone = true;
    }
  }
  return true;
}
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>

#define _DirDelim '/'
static int match_multi (const char **mask, const char **string)
{
  const char *msk;
  const char *str;
  const char *msktop;
  const char *strtop;

  msk = *mask;
  str = *string;

  while ((*msk != '\0') && (*msk == '*'))
    msk++;                      /* get rid of multiple '*'s */

  if (*msk == '\0')				/* '*' was last, auto-match */
    return +1;

  msktop = msk;
  strtop = str;

  while (*msk != '\0')
  {
    if (*msk == '*')
    {
      *mask = msk;
      *string = str;
      return 0;                 /* matched this segment */
    }
    else if (*str == '\0')
      return -1;                /* can't match */
    else
    {
      if ((*msk == '?') || (*msk == *str))
      {
	msk++;
	str++;
	if ((*msk == '\0') && (*str != '\0'))	/* advanced check */
	{
	  str++;
	  strtop++;
	  str = strtop;
	  msk = msktop;
	}
      }
      else
      {
	str++;
	strtop++;
	str = strtop;
	msk = msktop;
      }
    }
  }

  *mask = msk;
  *string = str;
  return +1;											 /* full match */
}

static int match_mask (const char *mask, const char *string)
{
  if (mask == NULL)
    return 0;

  if (string == NULL)
    return 0;

  if ((mask[0] == '*') && (mask[1] == '\0'))
    return 1;									/* instant match */

  while (*mask != '\0')
  {
    if (*mask == '*')
    {
      mask++;
      switch (match_multi (&mask, &string))
      {
      case +1:
	return 1;
      case -1:
	return 0;
      }
    }
    else if (*string == '\0')
      return 0;
    else if ((*mask == '?') || (*mask == *string))
    {
      mask++;
      string++;
    }
    else
      return 0;
  }

  if (*string == '\0')
    return 1;
  else
    return 0;
}

bool LinuxAddFileStack ( const char *szPathName, const char* fileMask, bool bRecursive, std::vector<std::string> &list, bool justDirs = false )
{
  DIR	*directory;
  dirent	*fileInfo;
  struct stat	statbuf;
  char	searchstr[1024];
  std::string	FilePath;

  strcpy(searchstr, szPathName);
  if (searchstr[strlen(searchstr) - 1] != '/')
    strcat(searchstr, "/");
  directory = opendir(searchstr);
  if (!directory)
    return false;

  // TODO: make it use the filemask
  while ((fileInfo = readdir(directory)))
  {
    if (!((strcmp(fileInfo->d_name, ".") == 0) || (strcmp(fileInfo->d_name, "..") == 0)))
    {
      FilePath = searchstr;
      FilePath += fileInfo->d_name;

      stat(FilePath.c_str(), &statbuf);

      if (justDirs && S_ISDIR(statbuf.st_mode))	// we never do just dirs recrusively
	list.push_back(FilePath);
      else if (!justDirs)
      {
	if (S_ISDIR(statbuf.st_mode) && bRecursive)
	  LinuxAddFileStack(FilePath.c_str(),fileMask,bRecursive, list);
	else if (match_mask (fileMask, fileInfo->d_name))
	  list.push_back(FilePath);
      }
    }
  }
  closedir(directory);
  return true;
}
#endif

std::string convertPathToDelims ( const char* file )  // ensures all the delims are constant
{
  if (!file)
    return std::string();

  std::string delim;
  delim += _DirDelim;
  return replace_all(replace_all(file,"/",delim),"\\",delim);
}

std::vector<std::string> getFilesInDir ( const char* dir, const char* filter, bool recrusive )
{
  std::vector<std::string> list;
  if (!dir)
    return list;

  std::string realFilter = "*.*";
  if ( filter )
    realFilter = filter;

  std::string directory  = convertPathToDelims(dir);

#ifdef _WIN32
  WindowsAddFileStack (directory.c_str(), realFilter.c_str(),recrusive,list);
#else
  LinuxAddFileStack(directory.c_str(), realFilter.c_str(),recrusive,list);
#endif
  return list;
}

std::vector<std::string> getDirsInDir ( const char* dir)
{
  std::vector<std::string> list;
  if (!dir)
    return list;

  std::string directory  = convertPathToDelims(dir);

#ifdef _WIN32
  WindowsAddFileStack (directory.c_str(), "*.*",false,list,true);
#else
  LinuxAddFileStack (directory.c_str(), "*.*",false,list,true);
#endif
  return list;
}

std::string getPathForOS ( const char* file )
{
  return convertPathToDelims(file);
}

std::string getFileDir ( const char* file )
{
  std::string f = convertPathToDelims(file);

  char *p = (char*)strrchr(f.c_str(),_DirDelim);
  if (p)				     // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    *(p+1) = 0;

  return std::string(f.c_str());
}

std::string getFileExtension ( const char* file )
{
  std::string f = convertPathToDelims(file);

  char *p = (char*)strrchr(f.c_str(),'.');
  if (!p)				   // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    return std::string();

  return std::string(p+1);
}

std::string getFileTitle ( const char* file )
{
  std::string f = convertPathToDelims(file);

  std::string temp = f;

  const char *p = strrchr(f.c_str(),_DirDelim);
  if (p)				  // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    temp = p+1;

  char *p2 = (char*)strrchr(temp.c_str(),'.');
  if (p2)				  // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    *(p2+1) = 0;

  return std::string(temp.c_str());
}

std::string getFileText ( const char* file )
{
  std::string text;
  if (!file)
    return text;

  FILE *fp = fopen(convertPathToDelims(file).c_str(),"rb");
  if (!fp)
    return text;

  fseek(fp,0,SEEK_END);
  unsigned int i  = (unsigned int)ftell(fp);
  fseek(fp,0,SEEK_SET);

  char *temp = (char*)malloc(i+1);
  fread(temp,i,1,fp);
  temp[i] = 0;
  text = temp;
  free(temp);
  fclose(fp);

  return replace_all(text,"\r",std::string());
}

std::vector<std::string> getFileTextLines ( const char* file )
{
  return tokenize(getFileText(file),"\n",0,false);
}

unsigned int getFileLen ( const char* file )
{
  if (!file)
    return 0;

  FILE *fp = fopen(convertPathToDelims(file).c_str(),"rb");
  if (!fp)
    return 0;

  fseek(fp,0,SEEK_END);
  unsigned int i  = (unsigned int)ftell(fp);
  fclose(fp);

  return i;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>use compare_nocase instead of stricmp<commit_after>/* bzflag
* Copyright (c) 1993 - 2008 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <stdio.h>
#include <stdarg.h>
#include <sstream>
#include "plugin_files.h"
#include "plugin_utils.h"

#ifdef _WIN32
#define _DirDelim '\\'

#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <io.h>
#include <direct.h>

bool WindowsAddFileStack ( const char *szPathName, const char* fileMask, bool bRecursive,std::vector<std::string> &list, bool justDirs = false )
{
  struct _finddata_t fileInfo;

  long		hFile;
  std::string searchstr;

  std::string FilePath;

  bool	bDone = false;

  searchstr = szPathName;
  searchstr += "\\";
  if (bRecursive)
    searchstr += "*.*";
  else if (fileMask)
    searchstr += fileMask;
  else
    searchstr += "*.*";

  std::string extenstionSearch;

  if ( fileMask && strchr(fileMask,'.'))
    extenstionSearch = strchr(fileMask,'.')+1;

  hFile = (long)_findfirst(searchstr.c_str(),&fileInfo);

  if (hFile != -1)
  {
    while (!bDone)
    {
      if ((strlen(fileInfo.name) >0) && (strcmp(fileInfo.name,".") != 0) &&
	(strcmp(fileInfo.name,"..") != 0))
      {
	FilePath = szPathName;
	//if (!(fileInfo.attrib & _A_SUBDIR ))
	  FilePath += "\\";
	FilePath += fileInfo.name;

	if (justDirs && (fileInfo.attrib & _A_SUBDIR ))	// we neever do just dirs recrusively
	  list.push_back(FilePath);
	else if (!justDirs)
	{
	  if ( (fileInfo.attrib & _A_SUBDIR ) && bRecursive)
	    WindowsAddFileStack(FilePath.c_str(),fileMask,bRecursive,list);
	  else if (!(fileInfo.attrib & _A_SUBDIR) )
	  {
	    if (bRecursive && fileMask)	// if we are recusive we need to check extension manualy, so we get dirs and stuf
	    {
	      if (strrchr(FilePath.c_str(),'.'))
	      {
		if ( compare_nocase(std::string(strrchr(FilePath.c_str(),'.')+1), extenstionSearch ) == 0 )
		  list.push_back(FilePath);
	      }
	    }
	    else
	      list.push_back(FilePath);
	  }
	}
      }
      if (_findnext(hFile,&fileInfo) == -1)
	bDone = true;
    }
  }
  return true;
}
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>

#define _DirDelim '/'
static int match_multi (const char **mask, const char **string)
{
  const char *msk;
  const char *str;
  const char *msktop;
  const char *strtop;

  msk = *mask;
  str = *string;

  while ((*msk != '\0') && (*msk == '*'))
    msk++;                      /* get rid of multiple '*'s */

  if (*msk == '\0')				/* '*' was last, auto-match */
    return +1;

  msktop = msk;
  strtop = str;

  while (*msk != '\0')
  {
    if (*msk == '*')
    {
      *mask = msk;
      *string = str;
      return 0;                 /* matched this segment */
    }
    else if (*str == '\0')
      return -1;                /* can't match */
    else
    {
      if ((*msk == '?') || (*msk == *str))
      {
	msk++;
	str++;
	if ((*msk == '\0') && (*str != '\0'))	/* advanced check */
	{
	  str++;
	  strtop++;
	  str = strtop;
	  msk = msktop;
	}
      }
      else
      {
	str++;
	strtop++;
	str = strtop;
	msk = msktop;
      }
    }
  }

  *mask = msk;
  *string = str;
  return +1;											 /* full match */
}

static int match_mask (const char *mask, const char *string)
{
  if (mask == NULL)
    return 0;

  if (string == NULL)
    return 0;

  if ((mask[0] == '*') && (mask[1] == '\0'))
    return 1;									/* instant match */

  while (*mask != '\0')
  {
    if (*mask == '*')
    {
      mask++;
      switch (match_multi (&mask, &string))
      {
      case +1:
	return 1;
      case -1:
	return 0;
      }
    }
    else if (*string == '\0')
      return 0;
    else if ((*mask == '?') || (*mask == *string))
    {
      mask++;
      string++;
    }
    else
      return 0;
  }

  if (*string == '\0')
    return 1;
  else
    return 0;
}

bool LinuxAddFileStack ( const char *szPathName, const char* fileMask, bool bRecursive, std::vector<std::string> &list, bool justDirs = false )
{
  DIR	*directory;
  dirent	*fileInfo;
  struct stat	statbuf;
  char	searchstr[1024];
  std::string	FilePath;

  strcpy(searchstr, szPathName);
  if (searchstr[strlen(searchstr) - 1] != '/')
    strcat(searchstr, "/");
  directory = opendir(searchstr);
  if (!directory)
    return false;

  // TODO: make it use the filemask
  while ((fileInfo = readdir(directory)))
  {
    if (!((strcmp(fileInfo->d_name, ".") == 0) || (strcmp(fileInfo->d_name, "..") == 0)))
    {
      FilePath = searchstr;
      FilePath += fileInfo->d_name;

      stat(FilePath.c_str(), &statbuf);

      if (justDirs && S_ISDIR(statbuf.st_mode))	// we never do just dirs recrusively
	list.push_back(FilePath);
      else if (!justDirs)
      {
	if (S_ISDIR(statbuf.st_mode) && bRecursive)
	  LinuxAddFileStack(FilePath.c_str(),fileMask,bRecursive, list);
	else if (match_mask (fileMask, fileInfo->d_name))
	  list.push_back(FilePath);
      }
    }
  }
  closedir(directory);
  return true;
}
#endif

std::string convertPathToDelims ( const char* file )  // ensures all the delims are constant
{
  if (!file)
    return std::string();

  std::string delim;
  delim += _DirDelim;
  return replace_all(replace_all(file,"/",delim),"\\",delim);
}

std::vector<std::string> getFilesInDir ( const char* dir, const char* filter, bool recrusive )
{
  std::vector<std::string> list;
  if (!dir)
    return list;

  std::string realFilter = "*.*";
  if ( filter )
    realFilter = filter;

  std::string directory  = convertPathToDelims(dir);

#ifdef _WIN32
  WindowsAddFileStack (directory.c_str(), realFilter.c_str(),recrusive,list);
#else
  LinuxAddFileStack(directory.c_str(), realFilter.c_str(),recrusive,list);
#endif
  return list;
}

std::vector<std::string> getDirsInDir ( const char* dir)
{
  std::vector<std::string> list;
  if (!dir)
    return list;

  std::string directory  = convertPathToDelims(dir);

#ifdef _WIN32
  WindowsAddFileStack (directory.c_str(), "*.*",false,list,true);
#else
  LinuxAddFileStack (directory.c_str(), "*.*",false,list,true);
#endif
  return list;
}

std::string getPathForOS ( const char* file )
{
  return convertPathToDelims(file);
}

std::string getFileDir ( const char* file )
{
  std::string f = convertPathToDelims(file);

  char *p = (char*)strrchr(f.c_str(),_DirDelim);
  if (p)				     // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    *(p+1) = 0;

  return std::string(f.c_str());
}

std::string getFileExtension ( const char* file )
{
  std::string f = convertPathToDelims(file);

  char *p = (char*)strrchr(f.c_str(),'.');
  if (!p)				   // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    return std::string();

  return std::string(p+1);
}

std::string getFileTitle ( const char* file )
{
  std::string f = convertPathToDelims(file);

  std::string temp = f;

  const char *p = strrchr(f.c_str(),_DirDelim);
  if (p)				  // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    temp = p+1;

  char *p2 = (char*)strrchr(temp.c_str(),'.');
  if (p2)				  // it's ok to go one past, cus even if it's the end, that's the NULL char so we can set it to NULL again with out worry
    *(p2+1) = 0;

  return std::string(temp.c_str());
}

std::string getFileText ( const char* file )
{
  std::string text;
  if (!file)
    return text;

  FILE *fp = fopen(convertPathToDelims(file).c_str(),"rb");
  if (!fp)
    return text;

  fseek(fp,0,SEEK_END);
  unsigned int i  = (unsigned int)ftell(fp);
  fseek(fp,0,SEEK_SET);

  char *temp = (char*)malloc(i+1);
  fread(temp,i,1,fp);
  temp[i] = 0;
  text = temp;
  free(temp);
  fclose(fp);

  return replace_all(text,"\r",std::string());
}

std::vector<std::string> getFileTextLines ( const char* file )
{
  return tokenize(getFileText(file),"\n",0,false);
}

unsigned int getFileLen ( const char* file )
{
  if (!file)
    return 0;

  FILE *fp = fopen(convertPathToDelims(file).c_str(),"rb");
  if (!fp)
    return 0;

  fseek(fp,0,SEEK_END);
  unsigned int i  = (unsigned int)ftell(fp);
  fclose(fp);

  return i;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <cmath>

struct Car {
	std::vector<int> point_start;
	std::vector<int> point_stop;
	std::vector<int> point_current;

	Car(std::vector<int> point_start_, std::vector<int> point_stop_): point_start(point_start_), point_stop(point_stop_) {};
};

struct EuclideanDistance {
	inline double operator()(std::shared_ptr<Car> car) {
		const double x_diff = car->point_current[0] - car->point_stop[0];
		const double y_diff = car->point_current[1] - car->point_stop[1];
		const double result = std::sqrt(x_diff * x_diff + y_diff * y_diff);
		return result;
	}

};

template <class H> class Map{
	private:
		std::vector<std::shared_ptr<Car>> cars;
		std::vector<std::vector<int>> matrix;
		int rows;
		int cols;
		H heuristic;
	public:
		Map(int rows_ = 10, int cols_ = 10): rows(rows_), cols(cols_){
			this->matrix=std::vector<std::vector<int>>(rows, std::vector<int>(cols, 0));
		};
		void appendCar(std::shared_ptr<Car> car) {
			this->cars.push_back(car);
			matrix[car->point_start[0]][car->point_start[1]] = this->cars.size();
			car->point_current = car->point_start;
		}

		void appendCars(std::vector<std::shared_ptr<Car>> cars){
			this->cars.insert(this->cars.end(), cars.begin(), cars.end());
		}

		void print() {
			for (auto row: matrix) {
				for (auto elem: row) {
					std::cout << elem << " ";
				}
				std::cout << "\n";
			}
		}
		std::vector<std::vector<int>> generate_new_poses(auto point_current) {
			std::vector<std::vector<int>> new_poses;
			for (int i = -1; i++; i < 2) {
				 for (int j = -1; j++; j < 2) {
					if (i >= 0 && i < this->rows && j >= 0 && j < this->cols) {
				 		new_poses.push_back({point_current[0]+i,point_current[1]+j});
					}
				 }
			}
			return new_poses;
		}
		void move(int index_car) {
		}

		 void update() {

			 for (int index_car = 0; index_car++; index_car < this->cars.size()) {
				auto new_poses = generate_new_poses(this->cars[index_car]->point_current);
				if (new_poses.size() == 0) {
					std::cout<<"We lost the route\n";
					continue;
				}
				for (auto pose: new_poses) {
					 //this->move(index_car, pose);
					 std::cout << heuristic(this->cars[index_car]) << "\n";

				}
			 }
		}
};

int main () {
	int rows = 10;
	int cols = 10;

	auto car = std::make_shared<Car>(std::vector{0, 0}, std::vector{5, 5});
	auto car2 = std::make_shared<Car>(std::vector{2, 2}, std::vector{7, 7});
	auto map = Map<EuclideanDistance>();
	map.appendCar(car);
	map.appendCar(car2);
	map.print();

	int time_clocks = 30;
	for (int val = 0;  val < time_clocks; val++) {
		std::cout << "clock time="<<val<<"\n";
		map.update();
	}
	//std::for_each(std::begin(matrix), std::end(matrix), [] (auto & v) mutable { for (auto& e: v) std::cin >> e;});

}
<commit_msg>Added function to calculate min distance heuristic<commit_after>#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <cmath>

struct Car {
	std::vector<int> point_start;
	std::vector<int> point_stop;
	std::vector<int> point_current;

	Car(std::vector<int> point_start_, std::vector<int> point_stop_): point_start(point_start_), point_stop(point_stop_) {};
};

struct EuclideanDistance {
	inline double operator()(auto current_pos, auto new_pos) {
		const double x_diff = current_pos[0] - new_pos[0];
		const double y_diff = current_pos[1] - new_pos[1];
		const double result = std::sqrt(x_diff * x_diff + y_diff * y_diff);
		return result;
	}

};

template <class H> class Map{
	private:
		std::vector<std::shared_ptr<Car>> cars;
		std::vector<std::vector<int>> matrix;
		int rows;
		int cols;
		H heuristic;
	public:
		Map(int rows_ = 10, int cols_ = 10): rows(rows_), cols(cols_){
			this->matrix=std::vector<std::vector<int>>(rows, std::vector<int>(cols, 0));
		};
		void appendCar(std::shared_ptr<Car> car) {
			this->cars.push_back(car);
			matrix[car->point_start[0]][car->point_start[1]] = this->cars.size();
			car->point_current = car->point_start;
		}

		void appendCars(std::vector<std::shared_ptr<Car>> cars){
			this->cars.insert(this->cars.end(), cars.begin(), cars.end());
		}

		void print() {
			for (auto row: matrix) {
				for (auto elem: row) {
					std::cout << elem << " ";
				}
				std::cout << "\n";
			}
		}
		std::vector<std::vector<int>> generate_new_poses(auto point_current) {
			std::vector<std::vector<int>> new_poses;
			for (int i = -1; i++; i < 2) {
				 for (int j = -1; j++; j < 2) {
					if ((point_current[0] + i) >= 0 && (point_current[0] + i)  < this->rows && (point_current[1] + j)  >= 0 && (point_current[1] + j)  < this->cols) {
				 		new_poses.push_back({point_current[0]+i,point_current[1]+j});
					}
				 }
			}
			return new_poses;
		}
		void move(int index_car) {
		}
		 void update() {
			 for (int index_car = 0; index_car++; index_car < this->cars.size()) {
				auto current_pos = this->cars[index_car]->point_current;
				auto new_poses = generate_new_poses(current_pos);
				if (new_poses.size() == 0) {
					std::cout<<"We lost the route\n";
					continue;
				}
				auto min_pos = current_pos;
				double min_value = -1.;
				for (auto pose: new_poses) {
					 double distanc = heuristic(current_pos, pose);
					 std::cout << distanc << "\n";
					 if (min_value == -1. || distanc < min_value) {
					 	min_pos = pose;
						min_value = distanc;
					 }

				}
			 }
		}
};

int main () {
	int rows = 10;
	int cols = 10;

	auto car = std::make_shared<Car>(std::vector{0, 0}, std::vector{5, 5});
	auto car2 = std::make_shared<Car>(std::vector{2, 2}, std::vector{7, 7});
	auto map = Map<EuclideanDistance>();
	map.appendCar(car);
	map.appendCar(car2);
	map.print();

	int time_clocks = 30;
	for (int val = 0;  val < time_clocks; val++) {
		std::cout << "clock time="<<val<<"\n";
		map.update();
	}
	//std::for_each(std::begin(matrix), std::end(matrix), [] (auto & v) mutable { for (auto& e: v) std::cin >> e;});

}
<|endoftext|>