perlglue.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. #ifdef SLIC3RXS
  2. #include <xsinit.h>
  3. namespace Slic3r {
  4. REGISTER_CLASS(ExPolygon, "ExPolygon");
  5. REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
  6. REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
  7. REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
  8. REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
  9. REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
  10. REGISTER_CLASS(ExtrusionSimulator, "ExtrusionSimulator");
  11. REGISTER_CLASS(Filler, "Filler");
  12. REGISTER_CLASS(Flow, "Flow");
  13. REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
  14. REGISTER_CLASS(GCode, "GCode");
  15. REGISTER_CLASS(Layer, "Layer");
  16. REGISTER_CLASS(SupportLayer, "Layer::Support");
  17. REGISTER_CLASS(LayerRegion, "Layer::Region");
  18. REGISTER_CLASS(Line, "Line");
  19. REGISTER_CLASS(Linef3, "Linef3");
  20. REGISTER_CLASS(PerimeterGenerator, "Layer::PerimeterGenerator");
  21. REGISTER_CLASS(PlaceholderParser, "GCode::PlaceholderParser");
  22. REGISTER_CLASS(Polygon, "Polygon");
  23. REGISTER_CLASS(Polyline, "Polyline");
  24. REGISTER_CLASS(PolylineCollection, "Polyline::Collection");
  25. REGISTER_CLASS(Print, "Print");
  26. REGISTER_CLASS(PrintObject, "Print::Object");
  27. REGISTER_CLASS(PrintRegion, "Print::Region");
  28. REGISTER_CLASS(Model, "Model");
  29. REGISTER_CLASS(ModelMaterial, "Model::Material");
  30. REGISTER_CLASS(ModelObject, "Model::Object");
  31. REGISTER_CLASS(ModelVolume, "Model::Volume");
  32. REGISTER_CLASS(ModelInstance, "Model::Instance");
  33. REGISTER_CLASS(BoundingBox, "Geometry::BoundingBox");
  34. REGISTER_CLASS(BoundingBoxf, "Geometry::BoundingBoxf");
  35. REGISTER_CLASS(BoundingBoxf3, "Geometry::BoundingBoxf3");
  36. REGISTER_CLASS(BridgeDetector, "BridgeDetector");
  37. REGISTER_CLASS(Point, "Point");
  38. __REGISTER_CLASS(Vec2d, "Pointf");
  39. __REGISTER_CLASS(Vec3d, "Pointf3");
  40. REGISTER_CLASS(DynamicPrintConfig, "Config");
  41. REGISTER_CLASS(StaticPrintConfig, "Config::Static");
  42. REGISTER_CLASS(PrintObjectConfig, "Config::PrintObject");
  43. REGISTER_CLASS(PrintRegionConfig, "Config::PrintRegion");
  44. REGISTER_CLASS(GCodeConfig, "Config::GCode");
  45. REGISTER_CLASS(PrintConfig, "Config::Print");
  46. REGISTER_CLASS(FullPrintConfig, "Config::Full");
  47. REGISTER_CLASS(Surface, "Surface");
  48. REGISTER_CLASS(SurfaceCollection, "Surface::Collection");
  49. REGISTER_CLASS(PrintObjectSupportMaterial, "Print::SupportMaterial2");
  50. REGISTER_CLASS(TriangleMesh, "TriangleMesh");
  51. SV* ConfigBase__as_hash(ConfigBase* THIS)
  52. {
  53. HV* hv = newHV();
  54. for (auto &key : THIS->keys())
  55. (void)hv_store(hv, key.c_str(), key.length(), ConfigBase__get(THIS, key), 0);
  56. return newRV_noinc((SV*)hv);
  57. }
  58. SV* ConfigBase__get(ConfigBase* THIS, const t_config_option_key &opt_key)
  59. {
  60. ConfigOption *opt = THIS->option(opt_key, false);
  61. return (opt == nullptr) ?
  62. &PL_sv_undef :
  63. ConfigOption_to_SV(*opt, *THIS->def()->get(opt_key));
  64. }
  65. SV* ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def)
  66. {
  67. switch (def.type) {
  68. case coFloat:
  69. case coPercent:
  70. return newSVnv(static_cast<const ConfigOptionFloat*>(&opt)->value);
  71. case coFloats:
  72. case coPercents:
  73. {
  74. auto optv = static_cast<const ConfigOptionFloats*>(&opt);
  75. AV* av = newAV();
  76. av_fill(av, optv->values.size()-1);
  77. for (const double &v : optv->values)
  78. av_store(av, &v - optv->values.data(), newSVnv(v));
  79. return newRV_noinc((SV*)av);
  80. }
  81. case coInt:
  82. return newSViv(static_cast<const ConfigOptionInt*>(&opt)->value);
  83. case coInts:
  84. {
  85. auto optv = static_cast<const ConfigOptionInts*>(&opt);
  86. AV* av = newAV();
  87. av_fill(av, optv->values.size()-1);
  88. for (const int &v : optv->values)
  89. av_store(av, &v - optv->values.data(), newSViv(v));
  90. return newRV_noinc((SV*)av);
  91. }
  92. case coString:
  93. {
  94. auto optv = static_cast<const ConfigOptionString*>(&opt);
  95. // we don't serialize() because that would escape newlines
  96. return newSVpvn_utf8(optv->value.c_str(), optv->value.length(), true);
  97. }
  98. case coStrings:
  99. {
  100. auto optv = static_cast<const ConfigOptionStrings*>(&opt);
  101. AV* av = newAV();
  102. av_fill(av, optv->values.size()-1);
  103. for (const std::string &v : optv->values)
  104. av_store(av, &v - optv->values.data(), newSVpvn_utf8(v.c_str(), v.length(), true));
  105. return newRV_noinc((SV*)av);
  106. }
  107. case coPoint:
  108. return perl_to_SV_clone_ref(static_cast<const ConfigOptionPoint*>(&opt)->value);
  109. case coPoint3:
  110. return perl_to_SV_clone_ref(static_cast<const ConfigOptionPoint3*>(&opt)->value);
  111. case coPoints:
  112. {
  113. auto optv = static_cast<const ConfigOptionPoints*>(&opt);
  114. AV* av = newAV();
  115. av_fill(av, optv->values.size()-1);
  116. for (const Vec2d &v : optv->values)
  117. av_store(av, &v - optv->values.data(), perl_to_SV_clone_ref(v));
  118. return newRV_noinc((SV*)av);
  119. }
  120. case coBool:
  121. return newSViv(static_cast<const ConfigOptionBool*>(&opt)->value ? 1 : 0);
  122. case coBools:
  123. {
  124. auto optv = static_cast<const ConfigOptionBools*>(&opt);
  125. AV* av = newAV();
  126. av_fill(av, optv->values.size()-1);
  127. for (size_t i = 0; i < optv->values.size(); ++ i)
  128. av_store(av, i, newSViv(optv->values[i] ? 1 : 0));
  129. return newRV_noinc((SV*)av);
  130. }
  131. default:
  132. std::string serialized = opt.serialize();
  133. return newSVpvn_utf8(serialized.c_str(), serialized.length(), true);
  134. }
  135. }
  136. SV* ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t i)
  137. {
  138. ConfigOption* opt = THIS->option(opt_key, false);
  139. if (opt == nullptr)
  140. return &PL_sv_undef;
  141. const ConfigOptionDef* def = THIS->def()->get(opt_key);
  142. switch (def->type) {
  143. case coFloats:
  144. case coPercents:
  145. return newSVnv(static_cast<ConfigOptionFloats*>(opt)->get_at(i));
  146. case coInts:
  147. return newSViv(static_cast<ConfigOptionInts*>(opt)->get_at(i));
  148. case coStrings:
  149. {
  150. // we don't serialize() because that would escape newlines
  151. const std::string &val = static_cast<ConfigOptionStrings*>(opt)->get_at(i);
  152. return newSVpvn_utf8(val.c_str(), val.length(), true);
  153. }
  154. case coPoints:
  155. return perl_to_SV_clone_ref(static_cast<ConfigOptionPoints*>(opt)->get_at(i));
  156. case coBools:
  157. return newSViv(static_cast<ConfigOptionBools*>(opt)->get_at(i) ? 1 : 0);
  158. default:
  159. return &PL_sv_undef;
  160. }
  161. }
  162. bool ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
  163. {
  164. ConfigOption* opt = THIS->option(opt_key, true);
  165. if (opt == nullptr)
  166. CONFESS("Trying to set non-existing option");
  167. const ConfigOptionDef* def = THIS->def()->get(opt_key);
  168. if (opt->type() != def->type)
  169. CONFESS("Option type is different from the definition");
  170. switch (def->type) {
  171. case coFloat:
  172. if (!looks_like_number(value))
  173. return false;
  174. static_cast<ConfigOptionFloat*>(opt)->value = SvNV(value);
  175. break;
  176. case coFloats:
  177. {
  178. std::vector<double> &values = static_cast<ConfigOptionFloats*>(opt)->values;
  179. AV* av = (AV*)SvRV(value);
  180. const size_t len = av_len(av)+1;
  181. values.clear();
  182. values.reserve(len);
  183. for (size_t i = 0; i < len; ++ i) {
  184. SV** elem = av_fetch(av, i, 0);
  185. if (elem == NULL || !looks_like_number(*elem)) return false;
  186. values.emplace_back(SvNV(*elem));
  187. }
  188. break;
  189. }
  190. case coPercents:
  191. {
  192. std::vector<double> &values = static_cast<ConfigOptionPercents*>(opt)->values;
  193. AV* av = (AV*)SvRV(value);
  194. const size_t len = av_len(av)+1;
  195. values.clear();
  196. values.reserve(len);
  197. for (size_t i = 0; i < len; i++) {
  198. SV** elem = av_fetch(av, i, 0);
  199. if (elem == NULL || !looks_like_number(*elem)) return false;
  200. values.emplace_back(SvNV(*elem));
  201. }
  202. break;
  203. }
  204. case coInt:
  205. if (!looks_like_number(value)) return false;
  206. static_cast<ConfigOptionInt*>(opt)->value = SvIV(value);
  207. break;
  208. case coInts:
  209. {
  210. std::vector<int> &values = static_cast<ConfigOptionInts*>(opt)->values;
  211. AV* av = (AV*)SvRV(value);
  212. const size_t len = av_len(av)+1;
  213. values.clear();
  214. values.reserve(len);
  215. for (size_t i = 0; i < len; i++) {
  216. SV** elem = av_fetch(av, i, 0);
  217. if (elem == NULL || !looks_like_number(*elem)) return false;
  218. values.emplace_back(SvIV(*elem));
  219. }
  220. break;
  221. }
  222. case coString:
  223. static_cast<ConfigOptionString*>(opt)->value = std::string(SvPV_nolen(value), SvCUR(value));
  224. break;
  225. case coStrings:
  226. {
  227. std::vector<std::string> &values = static_cast<ConfigOptionStrings*>(opt)->values;
  228. AV* av = (AV*)SvRV(value);
  229. const size_t len = av_len(av)+1;
  230. values.clear();
  231. values.reserve(len);
  232. for (size_t i = 0; i < len; i++) {
  233. SV** elem = av_fetch(av, i, 0);
  234. if (elem == NULL) return false;
  235. values.emplace_back(std::string(SvPV_nolen(*elem), SvCUR(*elem)));
  236. }
  237. break;
  238. }
  239. case coPoint:
  240. return from_SV_check(value, &static_cast<ConfigOptionPoint*>(opt)->value);
  241. // case coPoint3:
  242. // not gonna fix it, die Perl die!
  243. // return from_SV_check(value, &static_cast<ConfigOptionPoint3*>(opt)->value);
  244. case coPoints:
  245. {
  246. std::vector<Vec2d> &values = static_cast<ConfigOptionPoints*>(opt)->values;
  247. AV* av = (AV*)SvRV(value);
  248. const size_t len = av_len(av)+1;
  249. values.clear();
  250. values.reserve(len);
  251. for (size_t i = 0; i < len; i++) {
  252. SV** elem = av_fetch(av, i, 0);
  253. Vec2d point(Vec2d::Zero());
  254. if (elem == NULL || !from_SV_check(*elem, &point)) return false;
  255. values.emplace_back(point);
  256. }
  257. break;
  258. }
  259. case coBool:
  260. static_cast<ConfigOptionBool*>(opt)->value = SvTRUE(value);
  261. break;
  262. case coBools:
  263. {
  264. std::vector<unsigned char> &values = static_cast<ConfigOptionBools*>(opt)->values;
  265. AV* av = (AV*)SvRV(value);
  266. const size_t len = av_len(av)+1;
  267. values.clear();
  268. values.reserve(len);
  269. for (size_t i = 0; i < len; i++) {
  270. SV** elem = av_fetch(av, i, 0);
  271. if (elem == NULL) return false;
  272. values.emplace_back(SvTRUE(*elem));
  273. }
  274. break;
  275. }
  276. default:
  277. if (! opt->deserialize(std::string(SvPV_nolen(value))))
  278. return false;
  279. }
  280. return true;
  281. }
  282. /* This method is implemented as a workaround for this typemap bug:
  283. https://rt.cpan.org/Public/Bug/Display.html?id=94110 */
  284. bool ConfigBase__set_deserialize(ConfigBase* THIS, const t_config_option_key &opt_key, SV* str)
  285. {
  286. size_t len;
  287. const char * c = SvPV(str, len);
  288. std::string value(c, len);
  289. return THIS->set_deserialize_nothrow(opt_key, value);
  290. }
  291. void ConfigBase__set_ifndef(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value, bool deserialize)
  292. {
  293. if (THIS->has(opt_key))
  294. return;
  295. if (deserialize)
  296. ConfigBase__set_deserialize(THIS, opt_key, value);
  297. else
  298. ConfigBase__set(THIS, opt_key, value);
  299. }
  300. bool StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value)
  301. {
  302. const ConfigOptionDef* optdef = THIS->def()->get(opt_key);
  303. if (optdef->shortcut.empty())
  304. return ConfigBase__set(THIS, opt_key, value);
  305. for (const t_config_option_key &key : optdef->shortcut)
  306. if (! StaticConfig__set(THIS, key, value))
  307. return false;
  308. return true;
  309. }
  310. SV* to_AV(ExPolygon* expolygon)
  311. {
  312. const unsigned int num_holes = expolygon->holes.size();
  313. AV* av = newAV();
  314. av_extend(av, num_holes); // -1 +1
  315. av_store(av, 0, perl_to_SV_ref(expolygon->contour));
  316. for (unsigned int i = 0; i < num_holes; i++) {
  317. av_store(av, i+1, perl_to_SV_ref(expolygon->holes[i]));
  318. }
  319. return newRV_noinc((SV*)av);
  320. }
  321. SV* to_SV_pureperl(const ExPolygon* expolygon)
  322. {
  323. const unsigned int num_holes = expolygon->holes.size();
  324. AV* av = newAV();
  325. av_extend(av, num_holes); // -1 +1
  326. av_store(av, 0, to_SV_pureperl(&expolygon->contour));
  327. for (unsigned int i = 0; i < num_holes; i++) {
  328. av_store(av, i+1, to_SV_pureperl(&expolygon->holes[i]));
  329. }
  330. return newRV_noinc((SV*)av);
  331. }
  332. void from_SV(SV* expoly_sv, ExPolygon* expolygon)
  333. {
  334. AV* expoly_av = (AV*)SvRV(expoly_sv);
  335. const unsigned int num_polygons = av_len(expoly_av)+1;
  336. expolygon->holes.resize(num_polygons-1);
  337. SV** polygon_sv = av_fetch(expoly_av, 0, 0);
  338. from_SV(*polygon_sv, &expolygon->contour);
  339. for (unsigned int i = 0; i < num_polygons-1; i++) {
  340. polygon_sv = av_fetch(expoly_av, i+1, 0);
  341. from_SV(*polygon_sv, &expolygon->holes[i]);
  342. }
  343. }
  344. void from_SV_check(SV* expoly_sv, ExPolygon* expolygon)
  345. {
  346. if (sv_isobject(expoly_sv) && (SvTYPE(SvRV(expoly_sv)) == SVt_PVMG)) {
  347. if (!sv_isa(expoly_sv, perl_class_name(expolygon)) && !sv_isa(expoly_sv, perl_class_name_ref(expolygon)))
  348. CONFESS("Not a valid %s object", perl_class_name(expolygon));
  349. // a XS ExPolygon was supplied
  350. *expolygon = *(ExPolygon *)SvIV((SV*)SvRV( expoly_sv ));
  351. } else {
  352. // a Perl arrayref was supplied
  353. from_SV(expoly_sv, expolygon);
  354. }
  355. }
  356. void from_SV(SV* line_sv, Line* THIS)
  357. {
  358. AV* line_av = (AV*)SvRV(line_sv);
  359. from_SV_check(*av_fetch(line_av, 0, 0), &THIS->a);
  360. from_SV_check(*av_fetch(line_av, 1, 0), &THIS->b);
  361. }
  362. void from_SV_check(SV* line_sv, Line* THIS)
  363. {
  364. if (sv_isobject(line_sv) && (SvTYPE(SvRV(line_sv)) == SVt_PVMG)) {
  365. if (!sv_isa(line_sv, perl_class_name(THIS)) && !sv_isa(line_sv, perl_class_name_ref(THIS)))
  366. CONFESS("Not a valid %s object", perl_class_name(THIS));
  367. *THIS = *(Line*)SvIV((SV*)SvRV( line_sv ));
  368. } else {
  369. from_SV(line_sv, THIS);
  370. }
  371. }
  372. SV* to_AV(Line* THIS)
  373. {
  374. AV* av = newAV();
  375. av_extend(av, 1);
  376. av_store(av, 0, perl_to_SV_ref(THIS->a));
  377. av_store(av, 1, perl_to_SV_ref(THIS->b));
  378. return newRV_noinc((SV*)av);
  379. }
  380. SV* to_SV_pureperl(const Line* THIS)
  381. {
  382. AV* av = newAV();
  383. av_extend(av, 1);
  384. av_store(av, 0, to_SV_pureperl(&THIS->a));
  385. av_store(av, 1, to_SV_pureperl(&THIS->b));
  386. return newRV_noinc((SV*)av);
  387. }
  388. void from_SV(SV* poly_sv, MultiPoint* THIS)
  389. {
  390. AV* poly_av = (AV*)SvRV(poly_sv);
  391. const unsigned int num_points = av_len(poly_av)+1;
  392. THIS->points.resize(num_points);
  393. for (unsigned int i = 0; i < num_points; i++) {
  394. SV** point_sv = av_fetch(poly_av, i, 0);
  395. from_SV_check(*point_sv, &THIS->points[i]);
  396. }
  397. }
  398. void from_SV_check(SV* poly_sv, MultiPoint* THIS)
  399. {
  400. if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) {
  401. *THIS = *(MultiPoint*)SvIV((SV*)SvRV( poly_sv ));
  402. } else {
  403. from_SV(poly_sv, THIS);
  404. }
  405. }
  406. SV* to_AV(MultiPoint* THIS)
  407. {
  408. const unsigned int num_points = THIS->points.size();
  409. AV* av = newAV();
  410. if (num_points > 0) av_extend(av, num_points-1);
  411. for (unsigned int i = 0; i < num_points; i++) {
  412. av_store(av, i, perl_to_SV_ref(THIS->points[i]));
  413. }
  414. return newRV_noinc((SV*)av);
  415. }
  416. SV* to_SV_pureperl(const MultiPoint* THIS)
  417. {
  418. const unsigned int num_points = THIS->points.size();
  419. AV* av = newAV();
  420. if (num_points > 0) av_extend(av, num_points-1);
  421. for (unsigned int i = 0; i < num_points; i++) {
  422. av_store(av, i, to_SV_pureperl(&THIS->points[i]));
  423. }
  424. return newRV_noinc((SV*)av);
  425. }
  426. void from_SV_check(SV* poly_sv, Polygon* THIS)
  427. {
  428. if (sv_isobject(poly_sv) && !sv_isa(poly_sv, perl_class_name(THIS)) && !sv_isa(poly_sv, perl_class_name_ref(THIS)))
  429. CONFESS("Not a valid %s object", perl_class_name(THIS));
  430. from_SV_check(poly_sv, (MultiPoint*)THIS);
  431. }
  432. void from_SV_check(SV* poly_sv, Polyline* THIS)
  433. {
  434. if (!sv_isa(poly_sv, perl_class_name(THIS)) && !sv_isa(poly_sv, perl_class_name_ref(THIS)))
  435. CONFESS("Not a valid %s object", perl_class_name(THIS));
  436. from_SV_check(poly_sv, (MultiPoint*)THIS);
  437. }
  438. SV* to_SV_pureperl(const Point* THIS)
  439. {
  440. AV* av = newAV();
  441. av_fill(av, 1);
  442. av_store(av, 0, newSViv((*THIS)(0)));
  443. av_store(av, 1, newSViv((*THIS)(1)));
  444. return newRV_noinc((SV*)av);
  445. }
  446. void from_SV(SV* point_sv, Point* point)
  447. {
  448. AV* point_av = (AV*)SvRV(point_sv);
  449. // get a double from Perl and round it, otherwise
  450. // it would get truncated
  451. (*point) = Point(SvNV(*av_fetch(point_av, 0, 0)), SvNV(*av_fetch(point_av, 1, 0)));
  452. }
  453. void from_SV_check(SV* point_sv, Point* point)
  454. {
  455. if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
  456. if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point)))
  457. CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv))));
  458. *point = *(Point*)SvIV((SV*)SvRV( point_sv ));
  459. } else {
  460. from_SV(point_sv, point);
  461. }
  462. }
  463. SV* to_SV_pureperl(const Vec2d* point)
  464. {
  465. AV* av = newAV();
  466. av_fill(av, 1);
  467. av_store(av, 0, newSVnv((*point)(0)));
  468. av_store(av, 1, newSVnv((*point)(1)));
  469. return newRV_noinc((SV*)av);
  470. }
  471. bool from_SV(SV* point_sv, Vec2d* point)
  472. {
  473. AV* point_av = (AV*)SvRV(point_sv);
  474. SV* sv_x = *av_fetch(point_av, 0, 0);
  475. SV* sv_y = *av_fetch(point_av, 1, 0);
  476. if (!looks_like_number(sv_x) || !looks_like_number(sv_y)) return false;
  477. *point = Vec2d(SvNV(sv_x), SvNV(sv_y));
  478. return true;
  479. }
  480. bool from_SV_check(SV* point_sv, Vec2d* point)
  481. {
  482. if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
  483. if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point)))
  484. CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv))));
  485. *point = *(Vec2d*)SvIV((SV*)SvRV( point_sv ));
  486. return true;
  487. } else {
  488. return from_SV(point_sv, point);
  489. }
  490. }
  491. void from_SV_check(SV* surface_sv, Surface* THIS)
  492. {
  493. if (!sv_isa(surface_sv, perl_class_name(THIS)) && !sv_isa(surface_sv, perl_class_name_ref(THIS)))
  494. CONFESS("Not a valid %s object", perl_class_name(THIS));
  495. // a XS Surface was supplied
  496. *THIS = *(Surface *)SvIV((SV*)SvRV( surface_sv ));
  497. }
  498. SV* to_SV(TriangleMesh* THIS)
  499. {
  500. SV* sv = newSV(0);
  501. sv_setref_pv( sv, perl_class_name(THIS), (void*)THIS );
  502. return sv;
  503. }
  504. }
  505. #endif