// This file is a part of the Framsticks GDK. // Copyright (C) 1999-2014 Maciej Komosinski and Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.framsticks.com/ for further information. #include "geometrytestutils.h" #include "../genotypeloader.h" #include #include #include #include int printGenotypesList(const char *file) { long count = 0; long totalSize = 0; MiniGenotypeLoader loader(file); MiniGenotype *genotype; while (genotype = loader.loadNextGenotype()) { count++; totalSize += genotype->genotype.len(); fprintf(stderr, "%d. (%6d chars) %s\n", count, genotype->genotype.len(), (const char*)genotype->name); } if (loader.getStatus() == MiniGenotypeLoader::OnError) { fprintf(stderr, "Error: %s\n", (const char*)loader.getError()); return 2; } else { fprintf(stderr, "\ntotal: %d items, %d chars\n", count, totalSize); return 0; } } class TestInvoker { public: virtual void operator()(Model &model) = 0; }; int executeTestUsingLoadedModel(const char *file, const char *genoId, TestInvoker &test) { const char* genoName = genoId; const int genoIndex = isdigit(genoId[0]) ? atol(genoId) : 0; long count = 0; MiniGenotypeLoader loader(file); MiniGenotype *genotype; while (genotype = loader.loadNextGenotype()) { count++; if ((genoIndex == count) || (strcmp((const char*)genotype->name, genoName) == 0)) { Model model(genotype->genotype); if (!model.isValid()) { fprintf(stderr, "Cannot build Model from this genotype!\n"); return 4; } test(model); return 0; } } if (loader.getStatus() == MiniGenotypeLoader::OnError) { fprintf(stderr, "Error: %s\n", (const char*)loader.getError()); return 2; } else { fprintf(stderr, "Genotype %s not found in %s\n", genoId, file); return 3; } } int executeTestUsingRandomModel(int shape, TestInvoker &test) { Model model; model.open(); if ((shape < 1) || (shape > 3)) { shape = (rand()%3) + 1; } Part *part = model.addNewPart(Part::Shape(shape)); GeometryTestUtils::randomizePositionScaleAndOrient(part); model.close(); test(model); GeometryTestUtils::describePart(part, stdout); } class ModelBasedTestInvoker: public TestInvoker { private: void (*test)(Model &); public: ModelBasedTestInvoker(void (*_test)(Model &)): test(_test) {} void operator()(Model &model) { test(model); } }; int GeometryTestUtils::execute(const SString header, int argc, char *argv[], void (*test)(Model &)) { srand(time(NULL)); if ((argc == 3) && (strcmp("-l", argv[1]) == 0)) { return printGenotypesList(argv[2]); } if ((argc == 4) && (strcmp("-l", argv[1]) == 0)) { ModelBasedTestInvoker invoker(test); return executeTestUsingLoadedModel(argv[2], argv[3], invoker); } if ((argc == 2) && (strcmp("-c", argv[1]) == 0)) { ModelBasedTestInvoker invoker(test); return executeTestUsingRandomModel(-1, invoker); } if ((argc == 3) && (strcmp("-c", argv[1]) == 0) && isdigit(argv[2][0])) { int shape = atol(argv[2]); ModelBasedTestInvoker invoker(test); return executeTestUsingRandomModel(shape, invoker); } fprintf(stderr, "%s\n\n" "argument lists:\n" "-l FILENAME - to print list of models in file\n" "-l FILENAME GENO_ID - to load model from file and run test\n" "-c [SHAPE] - to create simple random model and run test\n\n" "FILENAME - name of file containing named f0 genotypes\n" "GENO_ID - either genotype name or index (1-based)\n" "SHAPE - 1=ellipsoid, 2=cuboid, 3=cylinder, others or none=random\n", (const char*)header); return 1; } class ModelAndDensityBasedTestInvoker: public TestInvoker { private: void (*test)(Model &, const double); double density; public: ModelAndDensityBasedTestInvoker(void (*_test)(Model &, const double), double _density): test(_test), density(_density) {} void operator()(Model &model) { test(model, density); } }; int GeometryTestUtils::execute(const SString header, int argc, char *argv[], void (*test)(Model &, const double)) { srand(time(NULL)); if ((argc == 3) && (strcmp("-l", argv[1]) == 0)) { return printGenotypesList(argv[2]); } if ((argc == 5) && (strcmp("-l", argv[1]) == 0) && isdigit(argv[4][0])) { double density = atol(argv[4]); ModelAndDensityBasedTestInvoker invoker(test, density); return executeTestUsingLoadedModel(argv[2], argv[3], invoker); } if ((argc == 3) && (strcmp("-c", argv[1]) == 0) && isdigit(argv[2][0])) { double density = atol(argv[2]); ModelAndDensityBasedTestInvoker invoker(test, density); return executeTestUsingRandomModel(-1, invoker); } if ((argc == 4) && (strcmp("-c", argv[1]) == 0) && isdigit(argv[2][0]) && isdigit(argv[3][0])) { double density = atol(argv[2]); int shape = atol(argv[3]); ModelAndDensityBasedTestInvoker invoker(test, density); return executeTestUsingRandomModel(shape, invoker); } fprintf(stderr, "%s\n\n" "argument lists:\n" "-l FILENAME - to print list of models in file\n" "-l FILENAME GENO_ID DENSITY - to load model from file and run test\n" "-c DENSITY [SHAPE] - to create simple random model and run test\n\n" "FILENAME - name of file containing named f0 genotypes\n" "GENO_ID - either genotype name or index (1-based)\n" "DENSITY - minimal number of samples per unit\n" "SHAPE - 1=ellipsoid, 2=cuboid, 3=cylinder, others or none=random", (const char*)header); return 1; } void GeometryTestUtils::addAnchorToModel(Model &model) { Part *part = model.addNewPart(Part::SHAPE_ELLIPSOID); part->p = Pt3D(0); part->scale = Pt3D(0.1); part->vcolor = Pt3D(1.0, 0.0, 1.0); addAxesToModel(Pt3D(0.5), Orient(Orient_1), Pt3D(0.0), model); } void GeometryTestUtils::addPointToModel(const Pt3D &markerLocation, Model &model) { Part *anchor = model.getPart(0); Part *part = model.addNewPart(Part::SHAPE_ELLIPSOID); part->p = Pt3D(markerLocation); part->scale = Pt3D(0.05); part->vcolor = Pt3D(1.0, 1.0, 0.0); model.addNewJoint(anchor, part, Joint::SHAPE_SOLID); } void GeometryTestUtils::addAxesToModel(const Pt3D &sizes, const Orient &axes, const Pt3D ¢er, Model &model) { Part *anchor = model.getPart(0); Part *part; part = model.addNewPart(Part::SHAPE_CUBOID); part->scale = Pt3D(sizes.x, 0.05, 0.05); part->setOrient(axes); part->p = center; part->vcolor = Pt3D(1.0, 0.0, 0.0); model.addNewJoint(anchor, part, Joint::SHAPE_SOLID); part = model.addNewPart(Part::SHAPE_CUBOID); part->scale = Pt3D(0.05, sizes.y, 0.05); part->setOrient(axes); part->p = center; part->vcolor = Pt3D(0.0, 1.0, 0.0); model.addNewJoint(anchor, part, Joint::SHAPE_SOLID); part = model.addNewPart(Part::SHAPE_CUBOID); part->scale = Pt3D(0.05, 0.05, sizes.z); part->setOrient(axes); part->p = center; part->vcolor = Pt3D(0.0, 0.0, 1.0); model.addNewJoint(anchor, part, Joint::SHAPE_SOLID); } void GeometryTestUtils::mergeModels(Model &target, Model &source) { Part *targetAnchor = target.getPart(0); Part *sourceAnchor = source.getPart(0); target.moveElementsFrom(source); target.addNewJoint(targetAnchor, sourceAnchor, Joint::SHAPE_SOLID); } double frand(double from, double width) { return from + width * ((rand()%10000) / 10000.0); } void GeometryTestUtils::randomizePositionScaleAndOrient(Part *part) { part->p = Pt3D(frand(1.5, 1.0), frand(1.5, 1.0), frand(1.5, 1.0)); part->scale = Pt3D(frand(0.1, 0.9), frand(0.1, 0.9), frand(0.1, 0.9)); part->setRot(Pt3D(frand(0.0, M_PI), frand(0.0, M_PI), frand(0.0, M_PI))); } void GeometryTestUtils::describePart(const Part *part, FILE *output) { fprintf(output, "# shape=%d\n", part->shape); fprintf(output, "# x=%f\n", part->p.x); fprintf(output, "# y=%f\n", part->p.y); fprintf(output, "# z=%f\n", part->p.z); fprintf(output, "# sx=%f\n", part->scale.x); fprintf(output, "# sy=%f\n", part->scale.y); fprintf(output, "# sz=%f\n", part->scale.z); fprintf(output, "# rx=%f\n", part->rot.x); fprintf(output, "# ry=%f\n", part->rot.y); fprintf(output, "# rz=%f\n", part->rot.z); }