def test_set_world_obj(self): class P(cqparts.Part): def make(self): return cadquery.Workplane('XY').box(1, 1, 1) p = P() p.world_coords = CoordSystem() self.assertIsNotNone(p.world_obj) with self.assertRaises(ValueError): p.world_obj = 'value is irrelevant'
def make_constraints(self): base = self.components['base'] top = self.components['top'] fastener = self.components['fastener'] return [ constraint.Fixed(base.mate_bottom), constraint.Coincident(top.mate_bottom, base.mate_top), constraint.Coincident(fastener.mate_origin, top.mate_top + CoordSystem((1, 2, 0))), ]
def test_rotation(self): (box1, box2) = (Box(), Box()) # set box1 world location: sit it on top of xy plane box1.world_coords = CoordSystem((0, 0, box1.height / 2)) # +'ve rotation c = Coincident(box2.mate_origin, box1.mate_top + CoordSystem(xDir=(1, 0.1, 0))) (part, coords) = list(solver([c]))[0] self.assertEqual(coords.origin, cadquery.Vector(0, 0, box1.height)) self.assertEqual(coords.xDir, cadquery.Vector(1, 0.1, 0).normalized()) self.assertEqual(coords.zDir, cadquery.Vector(0, 0, 1)) # -'ve rotation c = Coincident(box2.mate_origin + CoordSystem(xDir=(1, 0.1, 0)), box1.mate_top) (part, coords) = list(solver([c]))[0] self.assertEqual(coords.origin, cadquery.Vector(0, 0, box1.height)) self.assertEqual(coords.xDir, cadquery.Vector(1, -0.1, 0).normalized()) self.assertEqual(coords.zDir, cadquery.Vector(0, 0, 1))
def test_set_world_coords(self): class P(cqparts.Part): def make(self): return cadquery.Workplane('XY').box(1, 1, 1) p = P() self.assertIsNone(p.world_obj) p.world_coords = CoordSystem() self.assertIsNotNone(p.world_obj) p.world_coords = None self.assertIsNone(p.world_obj)
def make_constraints(self): bottom = self.components['bottom'] top = self.components['top'] spring = self.components['spring'] return [ constraint.Fixed(bottom.mate_side), constraint.Coincident( top.mate_spring_center, bottom.mate_spring_center + CoordSystem(normal=(0, 0, -1))), constraint.Coincident(spring.mate_origin, bottom.mate_spring_center), ]
def test_arithmetic_add_bad_type(self): with self.assertRaises(TypeError): CoordSystem.random() + 1 with self.assertRaises(TypeError): CoordSystem.random() + 'bad_type' with self.assertRaises(TypeError): CoordSystem.random() + None
def test_from_matrix(self): from FreeCAD import Matrix # identity self.assertEqual(CoordSystem.from_transform(Matrix()), CoordSystem()) # random #1 m = Matrix(-0.146655, -0.271161, -0.951296, 0.0376659, -0.676234, 0.729359, -0.103649, 0.615421, 0.721942, 0.628098, -0.290333, -0.451955, 0, 0, 0, 1) cs = CoordSystem.from_transform(m) self.assertEqual( cs, CoordSystem( origin=(0.0376659, 0.615421, -0.451955), xDir=(-0.14665525299526946, -0.6762339076811328, 0.7219417835748246), normal=(-0.9512957880009034, -0.10364897690151711, -0.2903329352984416), )) # random #2 m = Matrix(0.423408, -0.892837, -0.153517, -0.163654, -0.617391, -0.408388, 0.672345, 0.835824, -0.662989, -0.189896, -0.724144, 0.632804, 0, 0, 0, 1) cs = CoordSystem.from_transform(m) self.assertEqual( cs, CoordSystem( origin=(-0.163654, 0.835824, 0.632804), xDir=(0.4234078285564432, -0.6173904937335437, -0.6629892826920875), normal=(-0.15351701527110584, 0.672345066881529, -0.7241440720342351), ))
def display(*cadObjs, height=400, ortho=True, fov=0.2, debug=False, default_color=None): """ Jupyter 3D representation support """ if default_color is None: default_color = (0.9, 0.9, 0.9) def _display(cadObj): html = x3d_display(cadObj, export_edges=True, height=height, ortho=ortho, fov=fov, debug=debug) IPython.display.display(IPython.display.HTML(html)) if len(cadObjs) == 1: cadObj = cadObjs[0] else: cadObj = cq_jupyter.Assembly( [cq_jupyter.convert(cadObj) for cadObj in cadObjs]) if isinstance(cadObj, cadquery.Shape): part = cq_jupyter.Part(cadquery.CQ(cadObj), color=default_color) _display(cq_jupyter.Assembly([part])) elif isinstance(cadObj, cadquery.Workplane): part = cq_jupyter.Part(cadObj, color=default_color) _display(cq_jupyter.Assembly([part])) elif isinstance(cadObj, cq_jupyter.Assembly): _display(cadObj) elif isinstance(cadObj, (cq_jupyter.Part, cq_jupyter.Edges, cq_jupyter.Faces)): _display(cq_jupyter.Assembly([cadObj])) elif has_cqparts and isinstance(cadObj, cqparts.Assembly): cadObj.world_coords = CoordSystem() assembly = convertCqparts(cadObj) display(assembly) elif has_cqparts and isinstance(cadObj, cqparts.Part): part = cq_jupyter.Part(cadObj.local_obj, color=default_color) display(part) else: return cadObj
def apply(self, workplane, world_coords=CoordSystem()): """ Application of screwdrive indentation into a workplane (centred on the given world coordinates). :param workplane: workplane with solid to alter :type workplane: :class:`cadquery.Workplane` :param world_coords: coorindate system relative to ``workplane`` to move cutter before it's cut from the ``workplane`` :type world_coords: :class:`CoordSystem` """ self.world_coords = world_coords return workplane.cut(self.world_obj)
def make_constraints(self): constraints = [] index_width = int(math.sqrt(len(self.names))) for (i, name) in enumerate(self.names): (row, col) = ((i % index_width), int(i / index_width)) constraints.append( Fixed( self.components[name].mate_origin, CoordSystem(origin=(row * (self.box_size + self.gap), -col * (self.box_size + self.gap), 0)), )) return constraints
def make_constraints(self): return [ Fixed( self.components["middle"].mate_origin, CoordSystem(origin=(0, 0, self.base_height + self.thickness)), ), Coincident( self.components["lower"].mate_origin, self.components["middle"].mate_bottom(explode=self.explode), ), Coincident( self.components["upper"].mate_origin, self.components["middle"].mate_top(explode=self.explode), ), ]
def make_constraints(self): mates = [Fixed(self.components["case"].mate_origin)] # add the fasteners for i, j in enumerate(self.sp): m = Mate( self, CoordSystem( origin=(j.X, j.Y, self.height + self.thickness), xDir=(1, 0, 0), normal=(0, 0, 1), ), ) mates.append( Coincident(self.components[self.item_name(i)].mate_origin, m)) return mates
def make(self): # create inside cylinder inner_radius = self.effective_radius - (self.tooth_height / 2) gear = cadquery.Workplane('XY', origin=(0, 0, -self.width / 2)) \ .circle(inner_radius).extrude(self.width) # copy & rotate once per tooth tooth_template = self._make_tooth_template() period_arc = 360. / self.tooth_count for i in range(self.tooth_count): gear = gear.union(CoordSystem().rotated((0, 0, i * period_arc)) + tooth_template) return gear
def test_arithmetic_add_vector(self): # random 1 cs = CoordSystem( origin=(0.776696,-0.155044,0.464622), xDir=(-0.792263,-0.141302,0.593594), normal=(-0.586401,-0.0926133,-0.804709), ) v = Vector(0.894579,-0.282728,-0.428593) self.assertEqual( cs + v, Vector(0.3669727263895199, -0.5204201245493684, 1.3378492301899407) ) # random 2 cs = CoordSystem( origin=(-0.370354,-0.146263,-0.007179), xDir=(-0.96932,0.182199,-0.16499), normal=(0.244193,0.790464,-0.561726), ) v = Vector(-0.111398,-0.465007,-0.221905) self.assertEqual( cs + v, Vector(-0.3035072972382829, -0.613895258440105, -0.2411329328032198) )
def test_world2local(self): # random 1 cs = CoordSystem( origin=(-0.029, -0.222, 0.432), xDir=(0.556, -0.719, 0.417), normal=(0.779, 0.275, -0.564), ) self.assertMatrixAlmostEquals(cs.world_to_local_transform, [ 0.55584, -0.719063, 0.417122, -0.323709, -0.290761, -0.638252, -0.712806, 0.157808, 0.778781, 0.274923, -0.563842, 0.327197, 0, 0, 0, 1 ]) # random 2 cs = CoordSystem( origin=(-0.654, -0.75, 0.46), xDir=(-0.412, 0.906, -0.099), normal=(0.474, 0.306, 0.825), ) self.assertMatrixAlmostEquals(cs.world_to_local_transform, [ -0.412051, 0.905744, -0.0992066, 0.455462, -0.77801, -0.293074, 0.555706, -0.984248, 0.474252, 0.306163, 0.825439, 0.160081, 0, 0, 0, 1 ])
def make_constraints(self): constraints = [] length = len(self.coll) total = length * self.offset for i in range(len(self.coll)): constraints.append( Fixed( self.coll[i].mate_origin, CoordSystem( origin=(0, i * self.offset - (total / 2) + self.offset / 2, 0), xDir=(1, 0, 0), normal=(0, 0, 1), ), )) return constraints
def test_set_local_obj(self): class P(cqparts.Part): def make(self): return cadquery.Workplane('XY').box(1, 1, 1) p = P() p.world_coords = CoordSystem(origin=(0,0,10)) bb = p.world_obj.val().BoundingBox() self.assertAlmostEqual(bb.DiagonalLength, sqrt(3)) self.assertAlmostEqual((bb.zmin, bb.zmax), (-0.5 + 10, 0.5 + 10)) # change local p.local_obj = cadquery.Workplane('XY').box(10, 10, 10) bb = p.world_obj.val().BoundingBox() self.assertAlmostEqual(bb.DiagonalLength, sqrt(3) * 10) self.assertAlmostEqual((bb.zmin, bb.zmax), (-5 + 10, 5 + 10))
def get_mate_center(self, angle=0): """ Mate at ring's center rotated ``angle`` degrees. :param angle: rotation around z-axis (unit: deg) :type angle: :class:`float` :return: mate in ring's center rotated about z-axis :rtype: :class:`Mate <cqparts.constraint.Mate>` """ return Mate(self, CoordSystem.from_plane( cadquery.Plane( origin=(0, 0, self.width / 2), xDir=(1, 0, 0), normal=(0, 0, 1), ).rotated((0, 0, angle)) # rotate about z-axis ))
def test_world_coords(self): class C(cqparts.Component): def __init__(self, *args, **kwargs): self._flag_placement_changed = False super(C, self).__init__(*args, **kwargs) def _placement_changed(self): self._flag_placement_changed = True super(C, self)._placement_changed() c = C() self.assertIsNone(c.world_coords) cs = CoordSystem.random() self.assertFalse(c._flag_placement_changed) c.world_coords = cs self.assertTrue(c._flag_placement_changed) self.assertEquals(c.world_coords, cs) c.world_coords = None self.assertIsNone(c.world_coords)
def test_coincident_backward(self): (box1, box2) = (Box(), Box()) constraints = [ # stack box2 on box1 (in reversed logical order) Coincident(box2.mate_bottom, box1.mate_top), Fixed(box1.mate_bottom, CoordSystem()), ] solution = solver(constraints) # 1st solution : box1 (part, coords) = next(solution) self.assertEqual(id(part), id(box1)) part.world_coords = coords # 2nd solution : box2 (part, coords) = next(solution) self.assertEqual(id(part), id(box2)) with self.assertRaises(StopIteration): next(solution)
def make_constraints(self): # Pull out component references p1 = self.components['panel1'] p2 = self.components['panel2'] fastener = self.components['fastener'] return [ # Assembly's origin on panel1 Fixed(p1.mate_origin), # Join panel at the corner Coincident( p2.mate_end, p1.get_mate_edge(p2.thickness), ), # Fastener assembly in the middle of a Coincident( fastener.mate_origin, # mate_origin's -Z axis is used for evaluation p2.mate_end + CoordSystem( origin=(0, 0, 25), # 25mm above panel1 surface xDir=(0, -1, 0) # rotate so anchor faces inside ), ), ]
def test_arithmetic_sub_coordsys(self): # random 1 cs = CoordSystem( origin=(0.995014, 0.597397, 0.251518), xDir=(-0.701536, -0.665758, 0.254191), normal=(0.135645, 0.225422, 0.964772), ) cs_sub = CoordSystem( origin=(-0.320574, 0.951257, 0.176344), xDir=(-0.744255, -0.650638, -0.150844), normal=(0.419232, -0.279276, -0.863858), ) self.assertEqual( cs - cs_sub, CoordSystem( origin=(-0.7602379451931977, -0.9700309903527986, 0.5854211817688126), xDir=(0.9169464676048765, -0.22755650176590822, -0.32776090988859785), normal=(-0.39315299213245875, -0.37502955527701604, -0.8395138816279446), )) # random 2 cs = CoordSystem( origin=(-0.980361, 0.591789, -0.073316), xDir=(-0.27988, -0.085973, -0.956178), normal=(0.755724, 0.59451, -0.27466), ) cs_sub = CoordSystem( origin=(0.480657, 0.627596, 0.409464), xDir=(-0.0929824, -0.728202, 0.679026), normal=(0.549731, 0.531063, 0.644801), ) self.assertEqual( cs - cs_sub, CoordSystem( origin=(-0.1658962438630106, -1.02792754287956, -1.133479452321362), xDir=(-0.5606397275073202, 0.1404609281661355, -0.8160599387295184), normal=(-0.6896940658874535, 0.466189492307297, 0.5540662891224277), ))
def test_arithmetic_add_coordsys(self): # random 1 cs = CoordSystem( origin=(0.319872, -0.424248, -0.813118), xDir=(0.301597, 0.844131, -0.443263), normal=(0.518197, -0.535377, -0.666966), ) cs_add = CoordSystem( origin=(-0.965988, 0.438111, 0.447495), xDir=(-0.903357, 0.322463, -0.282777), normal=(0.0176109, -0.630881, -0.77568), ) self.assertEqual( cs + cs_add, CoordSystem( origin=(0.6110520112439473, -1.4667419254474168, -0.42101284070314754), xDir=(-0.16091098866905712, -0.6019554630954405, 0.7821491380645386), normal=(-0.901549677957146, 0.41213999099584614, 0.13171486627298448), )) # random 2 cs = CoordSystem( origin=(0.997758, -0.429350, 0.469693), xDir=(-0.949669, 0.304061, -0.0753356), normal=(-0.265922, -0.655403, 0.706917), ) cs_add = CoordSystem( origin=(0.604043, -0.918366, 0.765700), xDir=(-0.208045, 0.778042, 0.592762), normal=(0.591826, -0.382369, 0.709603), ) self.assertEqual( cs + cs_add, CoordSystem( origin=(0.3725549528751452, -0.1125950462339067, 1.6113356739288598), xDir=(-0.08887557530345871, -0.9896725888680419, -0.11246910223571256), normal=(-0.6874287881318142, -0.020766321770180177, 0.7259548340825087), ))
def make_constraints(self): constraints = [] ball_angle = -radians(self.angle * 2) rail_angle_delta = radians(self.angle / 2) for i in range(self.ball_count): # crude, innacruate calculation. justification: ball position is just illustrative ball = self.components[self.ball_name(i)] arc_angle = i * ((pi * 2) / self.ball_count) rail_angle = arc_angle + rail_angle_delta constraints.append(constraint.Fixed( ball.mate_origin, CoordSystem( origin=( self.rolling_radius * cos(rail_angle), self.rolling_radius * sin(rail_angle), 0, ), xDir=(cos(ball_angle), sin(ball_angle), 0), normal=(0, 0, 1), ) )) return constraints
def test_random_seed(self): for i in range(1, 5): cs1 = CoordSystem.random(seed=i) cs2 = CoordSystem.random(seed=i) # same seed self.assertEqual(cs1, cs2) # result should be the same
def test_random(self): cs = CoordSystem.random() self.assertIsInstance(cs, CoordSystem) self.assertNotEqual(cs, CoordSystem()) # not an identity matrix
def test_mate_origin(self): c = cqparts.Component() mate = c.mate_origin self.assertEquals(id(mate.component), id(c)) self.assertEquals(mate.local_coords, CoordSystem())
def mate_threadstart(self): return Mate(self, CoordSystem(origin=(0, 0, -self.neck_length)))
def test_repr(self): repr_str = repr(CoordSystem.random()) self.assertIsInstance(repr_str, str) self.assertTrue(bool(repr_str))
def get_mate_edge(self, thickness): return Mate( self, CoordSystem(origin=((self.length / 2) - (thickness / 2), 0, self.thickness / 2)))