diff --git a/CHANGELOG.md b/CHANGELOG.md index 19259eb..30895fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,9 @@ # Changelog -## Unreleased +## 2020-12-18 - 1.0.1 ### Added - -### Changed - -### Removed - +* Moved MeasurementPoint from grasshopper document to `compas_mobile_robot_reloc.utils`. ## 2020-12-18 - 1.0.0 diff --git a/grasshopper/robot_localization.ghx b/grasshopper/robot_localization.ghx index 9c0aa84..bd59c9f 100644 --- a/grasshopper/robot_localization.ghx +++ b/grasshopper/robot_localization.ghx @@ -69,10 +69,10 @@ - -1504 - -446 + 247 + 121 - 2.35919762 + 0.3605495 @@ -132,9 +132,9 @@ - 142 + 140 - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 @@ -1203,16 +1203,16 @@ 114.9603 - 653.6582 + 653.6581 114.9603 - 653.6582 - 210.7123 + 653.6581 + 210.7122 63.03317 - 210.7123 + 210.7122 A quick note Microsoft Sans Serif @@ -1229,7 +1229,7 @@ 58.03317 109.9603 - 600.6251 + 600.625 105.752 @@ -1255,12 +1255,9 @@ import csv import os -from collections import OrderedDict - import rhinoscriptsyntax as rs -import Rhino.Geometry as rg -from compas.geometry import Point +from compas_mobile_robot_reloc.utils import MeasurementPoint if len(prefixes) < 1: select_all = True @@ -1268,40 +1265,6 @@ else: select_all = False prefixes = [prefix.upper() for prefix in prefixes] -class MeasurementPt(object): - def __init__(self, pt_name, xyz, attrs={}): - self.pt_name = pt_name - self.xyz = xyz - self.x, self.y, self.z = xyz - self.attrs = attrs - - self.split_pt_name() - - def __repr__(self): - return "Point ID: {}, Location: {}, {}, {}".format(self.pt_name, *self.xyz) - - def as_cgpoint(self): - return Point(*self.xyz) - - def as_rgpoint(self): - return rg.Point3d(*self.xyz) - - def split_pt_name(self): - idx = "" - - for n, elem in enumerate(self.pt_name[::-1]): - if elem.isdigit(): - idx = elem + idx # add to front of str - else: - idx_last_char_idx = len(self.pt_name) - n - break - - self.prefix = self.pt_name[:idx_last_char_idx] - - try: - self.idx = int(idx) - except ValueError: - self.idx = 0 if cache_dir is None: cache_dir = os.path.dirname(rs.DocumentPath()) @@ -1336,11 +1299,11 @@ if os.path.exists(file_to_process): except ValueError: continue - xyz = [c * 1000 for c in xyz] + x, y, z = [c * 1000 for c in xyz] pt_name = pt_data.pop("NAME") - #print(pt_name) - measured_pts.append(MeasurementPt(pt_name, xyz, attrs=pt_data)) + + measured_pts.append(MeasurementPoint(x, y, z, pt_name, attrs=pt_data)) # raise if no points found if len(measured_pts) == 0: @@ -1373,7 +1336,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 958 207 @@ -1384,7 +1347,6 @@ ids = [pt.pt_name for pt in measured_pts] 1061 269 - true @@ -1418,7 +1380,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 960 209 @@ -1429,7 +1391,6 @@ ids = [pt.pt_name for pt in measured_pts] 1004.5 219 - true @@ -1449,7 +1410,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 960 229 @@ -1460,7 +1421,6 @@ ids = [pt.pt_name for pt in measured_pts] 1004.5 239 - true @@ -1481,7 +1441,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 960 249 @@ -1492,7 +1452,6 @@ ids = [pt.pt_name for pt in measured_pts] 1004.5 259 - true @@ -1512,7 +1471,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 960 269 @@ -1523,7 +1482,6 @@ ids = [pt.pt_name for pt in measured_pts] 1004.5 279 - true @@ -1544,7 +1502,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 960 289 @@ -1555,7 +1513,6 @@ ids = [pt.pt_name for pt in measured_pts] 1004.5 299 - true @@ -1577,7 +1534,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 960 309 @@ -1588,7 +1545,6 @@ ids = [pt.pt_name for pt in measured_pts] 1004.5 319 - true @@ -1604,7 +1560,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 1076 209 @@ -1615,7 +1571,6 @@ ids = [pt.pt_name for pt in measured_pts] 1089 229 - true @@ -1631,7 +1586,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 1076 249 @@ -1642,7 +1597,6 @@ ids = [pt.pt_name for pt in measured_pts] 1089 269 - true @@ -1658,7 +1612,7 @@ ids = [pt.pt_name for pt in measured_pts] - + 1076 289 @@ -1669,7 +1623,6 @@ ids = [pt.pt_name for pt in measured_pts] 1089 309 - true @@ -2318,11 +2271,11 @@ ids = [pt.pt_name for pt in measured_pts] 3247.588 - 679.0239 + 679.024 2321.27 - 679.0239 + 679.024 A quick note Microsoft Sans Serif @@ -2782,11 +2735,11 @@ if localization_origin_frame: 741.1973 - 2692.582 + 2692.581 741.1973 - 2692.582 + 2692.581 835.7286 @@ -2808,8 +2761,8 @@ if localization_origin_frame: 1958.138 736.1973 - 739.4436 - 104.5314 + 739.4434 + 104.5313 1963.138 @@ -3652,60 +3605,6 @@ transformation = cgtransformation_to_rgtransform(_transformation) - - 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe - Scribble - - - - - true - - 2099.8 - 1079.629 - - - 2308.736 - 1079.629 - - - 2308.736 - 1131.863 - - - 2099.8 - 1131.863 - - A quick note - Microsoft Sans Serif - 7943ddbb-7631-4d54-ad14-c027df3ea2dc - false - Scribble - Scribble - 25 - conda activate rcf -rcf proxy - - - - - - 2094.8 - 1074.629 - 218.9355 - 62.23401 - - - 2099.8 - 1079.629 - - - - - - - - fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -3741,7 +3640,7 @@ rcf proxy - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -3777,7 +3676,7 @@ rcf proxy - + 410755b1-224a-4c1e-a407-bf32fb45ea7e 00000000-0000-0000-0000-000000000000 @@ -4180,7 +4079,7 @@ else: - + 410755b1-224a-4c1e-a407-bf32fb45ea7e 00000000-0000-0000-0000-000000000000 @@ -4522,7 +4421,7 @@ if sticky["apl_result"] is not None: - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -4557,7 +4456,7 @@ if sticky["apl_result"] is not None: - + 410755b1-224a-4c1e-a407-bf32fb45ea7e 00000000-0000-0000-0000-000000000000 @@ -4567,8 +4466,7 @@ if sticky["apl_result"] is not None: from compas import json_load -from compas_rhino.utilities import unload_modules -unload_modules("compas_mobile_robot_reloc") + from compas_mobile_robot_reloc.utils import cgframe_to_rgplane import Rhino.Geometry as rg @@ -4704,7 +4602,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 06953bda-1d37-4d58-9b38-4b3c74e54c8f File Path @@ -4761,7 +4659,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 9ab93e1a-ebdf-4090-9296-b000cff7b202 Split List @@ -4903,7 +4801,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 1817fd29-20ae-4503-b542-f0fb651e67d7 List Length @@ -4989,7 +4887,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -5024,7 +4922,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 9ab93e1a-ebdf-4090-9296-b000cff7b202 Split List @@ -5166,7 +5064,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 1817fd29-20ae-4503-b542-f0fb651e67d7 List Length @@ -5252,7 +5150,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -5287,7 +5185,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5312,7 +5210,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -5347,7 +5245,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -5382,7 +5280,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -5417,7 +5315,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5442,7 +5340,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 28f40e48-e739-4211-91bd-f4aefa5965f8 Transform @@ -5477,7 +5375,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5502,7 +5400,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5527,7 +5425,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5552,7 +5450,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5577,7 +5475,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5602,7 +5500,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5627,7 +5525,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5652,7 +5550,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5677,84 +5575,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - - - 28f40e48-e739-4211-91bd-f4aefa5965f8 - Transform - - - - - Contains a collection of three-dimensional transformations - acdeb4d1-999a-4cd6-9e0d-ea2c0df4ae08 - Transform - Transform - false - 0 - - - - - - 1824 - 59 - 50 - 24 - - - 1849.049 - 71.82825 - - - - - - 1 - - - - - 1 - {0;0;0} - - - - - 1 - - - - - Generic - 0.63751297948073338 - -0.77043276933639726 - 0.00324791105910414 - 7315.0846573320905 - 0.77043830834011318 - 0.63751399837689271 - -0.00084552677788633877 - -25098.384917767537 - -0.0014191672286269555 - 0.0030413493974164032 - 0.99999436806325082 - -1211.8461418773127 - 0 - 0 - 0 - 1 - - - - - - - - - - - - - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5779,7 +5600,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5804,7 +5625,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5829,7 +5650,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5854,7 +5675,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5879,7 +5700,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 59e0b89a-e487-49f8-bab8-b5bab16be14c Panel @@ -5940,7 +5761,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5965,7 +5786,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -5990,7 +5811,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6015,7 +5836,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6040,7 +5861,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6065,7 +5886,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6090,7 +5911,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6115,7 +5936,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6140,7 +5961,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6165,7 +5986,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6190,7 +6011,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6215,7 +6036,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6240,7 +6061,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6265,7 +6086,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6290,7 +6111,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6315,7 +6136,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6340,7 +6161,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6365,7 +6186,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6390,7 +6211,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6415,7 +6236,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + 28f40e48-e739-4211-91bd-f4aefa5965f8 Transform @@ -6450,7 +6271,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6475,7 +6296,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6500,7 +6321,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6525,7 +6346,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6550,7 +6371,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6575,7 +6396,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6600,7 +6421,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6625,7 +6446,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6650,7 +6471,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6675,7 +6496,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6700,7 +6521,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -6839,7 +6660,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -6864,7 +6685,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + fbac3e32-f100-4292-8692-77240a42fd1a Point @@ -7003,7 +6824,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -7028,7 +6849,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -7065,7 +6886,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - + c552a431-af5b-46a9-a8a4-0fcbc27ef596 Group @@ -7097,7 +6918,7 @@ rcs_planes = [cgframe_to_rgplane(f) for f in frames] - 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 diff --git a/src/compas_mobile_robot_reloc/utils.py b/src/compas_mobile_robot_reloc/utils.py index abb1408..acfb905 100644 --- a/src/compas_mobile_robot_reloc/utils.py +++ b/src/compas_mobile_robot_reloc/utils.py @@ -1,6 +1,6 @@ """ ******************************************************************************** -compas_mobile_robot_reloc.utils +Utilities ******************************************************************************** """ from __future__ import absolute_import @@ -8,10 +8,10 @@ from __future__ import print_function import compas -import compas.geometry as cg +import compas.geometry try: - import Rhino.Geometry as rg + import Rhino.Geometry except ImportError: pass @@ -38,10 +38,12 @@ def _is_type_checking(): # type: () -> bool if TYPE_CHECKING: from typing import List + from typing import Tuple + from typing import Union def rgpoint_to_cgpoint(pt): - # type: (rg.Point3d) -> compas.geometry.Point + # type: (Rhino.Geometry.Point3d) -> compas.geometry.Point """Convert :class:`Rhino.Geometry.Point3d` to :class:`compas.geometry.Point`. Parameters @@ -53,32 +55,38 @@ def rgpoint_to_cgpoint(pt): ------- Resulting point object """ - return cg.Point(pt.X, pt.Y, pt.Z) + return compas.geometry.Point(pt.X, pt.Y, pt.Z) -def cgframe_to_rgplane(frame): # type: (compas.geometry.Frame) -> rg.Plane +def cgpoint_to_rgpoint(pt): + # type: (compas.geometry.Point) -> (Rhino.Geometry.Point3d) + """Convert :class:`compas.geometry.Point` to :class:`Rhino.Geometry.Point`.""" + return Rhino.Geometry.Point3d(*list(pt)) + + +def cgframe_to_rgplane(frame): # type: (compas.geometry.Frame) -> Rhino.Geometry.Plane """Convert :class:`compas.Geometry.Frame` to :class:`Rhino.Geometry.Plane`.""" # noqa: E501 - origin = rg.Point3d(*list(frame.point)) - x_vec = rg.Vector3d(*list(frame.xaxis)) - y_vec = rg.Vector3d(*list(frame.yaxis)) + origin = Rhino.Geometry.Point3d(*list(frame.point)) + x_vec = Rhino.Geometry.Vector3d(*list(frame.xaxis)) + y_vec = Rhino.Geometry.Vector3d(*list(frame.yaxis)) - return rg.Plane(origin, x_vec, y_vec) + return Rhino.Geometry.Plane(origin, x_vec, y_vec) def rgtransform_to_cgtransformation(rgT): - # type: (rg.Transform) -> cg.Transformation + # type: (Rhino.Geometry.Transform) -> compas.geometry.Transformation """Convert :class:`Rhino.Geometry.Transform` to :class:`compas.geometry.Transformation`.""" # noqa: E501 M = rgtransform_to_matrix(rgT) - return cg.Transformation.from_matrix(M) + return compas.geometry.Transformation.from_matrix(M) -def rgtransform_to_matrix(rgT): # type: (rg.Transform) -> List[List[float]] +def rgtransform_to_matrix(rgT): # type: (Rhino.Geometry.Transform) -> List[List[float]] """Convert :class:`Rhino.Geometry.Transform` to transformation matrix.""" return [[rgT.Item[i, j] for j in range(4)] for i in range(4)] def cgtransformation_to_rgtransform(cgT): - # type: (compas.geometry.Transformation) -> rg.Transform + # type: (compas.geometry.Transformation) -> Rhino.Geometry.Transform """Convert :class:`compas.geometry.Transformation` to :class:`Rhino.Geometry.Transform`.""" # noqa: E501 _ensure_rhino() @@ -87,14 +95,68 @@ def cgtransformation_to_rgtransform(cgT): return matrix_to_rgtransform(M) -def matrix_to_rgtransform(M): # type: (List[List[float]]) -> rg.Transform +def matrix_to_rgtransform(M): # type: (List[List[float]]) -> Rhino.Geometry.Transform """Create :class:`Rhino.Geometry.Transform` from a transformation matrix.""" _ensure_rhino() - rgT = rg.Transform() + rgT = Rhino.Geometry.Transform() for i, row in enumerate(M): for j, val in enumerate(row): rgT[i, j] = val return rgT + + +class MeasurementPoint(compas.geometry.Point): + """A :class:`compas.geometry.Point` with some CSV pointlist related methods.""" + + def __init__( + self, + x, # type: float + y, # type: float + z, # type: float + pt_name, # type: str + attrs=None, # type: Union[None, dict] + ): # type: (...) -> None + super(MeasurementPoint, self).__init__(x, y, z) + self.pt_name = pt_name + self.attrs = attrs or {} + + def __repr__(self): # type: () -> str + return "Point ID: {}, Location: {}, {}, {}".format( + self.pt_name, self.x, self.y, self.z + ) + + @property + def prefix(self): # type: () -> str + """Point prefix from data source.""" + return self._split_pt_name()[0] + + @property + def idx(self): # type: () -> int + """Point index from data source.""" + return self._split_pt_name()[1] + + def as_rgpoint(self): # type: () -> compas.geometry.Point + """Get a point representation in Rhino.""" + return cgpoint_to_rgpoint(self) + + def _split_pt_name(self): # type: () -> Tuple[str, int] + idx = "" + + for n, elem in enumerate(self.pt_name[::-1]): + if elem.isdigit(): + idx = elem + idx # add to front of str + else: + idx_last_char_idx = len(self.pt_name) - n + break + + prefix = self.pt_name[:idx_last_char_idx] + + try: + _idx = int(idx) + except ValueError: + _idx = 0 + + return prefix, _idx diff --git a/src/compas_mobile_robot_reloc/xforms.py b/src/compas_mobile_robot_reloc/xforms.py index c9a140f..84e3a0e 100644 --- a/src/compas_mobile_robot_reloc/xforms.py +++ b/src/compas_mobile_robot_reloc/xforms.py @@ -1,6 +1,6 @@ """ ******************************************************************************** -compas_mobile_robot_reloc.utils +Transformations ******************************************************************************** """ from __future__ import absolute_import