(* ISO 10303-508, TC 184/SC4/WG12 N571 *)
SCHEMA aic_non_manifold_surface; 
 
  USE FROM aic_topologically_bounded_surface;       -- ISO 10303-511
 
  USE FROM geometric_model_schema (                 -- ISO 10303-42
      face_based_surface_model); 
 
  USE FROM geometry_schema (                        -- ISO 10303-42
      b_spline_curve,
      b_spline_surface,
      bounded_pcurve,
      bounded_surface_curve,
      cartesian_transformation_operator_3d,
      curve, 
      curve_replica, 
      degenerate_pcurve, 
      evaluated_degenerate_pcurve, 
      intersection_curve, 
      offset_curve_3d, 
      offset_surface, 
      point_on_curve, 
      point_on_surface, 
      seam_curve, 
      surface, 
      surface_replica); 

  USE FROM product_property_representation_schema ( -- ISO 10303-41
      shape_representation); 
 
  USE FROM representation_schema (                  -- ISO 10303-43
      mapped_item,
      representation,
      representation_item,
      representation_map);
 
  USE FROM topology_schema (                        -- ISO 10303-42
      closed_shell,
      connected_face_set, 
      face,
      open_shell, 
      oriented_face);
 

ENTITY non_manifold_surface_shape_representation 
   SUBTYPE OF (shape_representation); 
WHERE 
  WR1: SIZEOF (QUERY (it <* SELF.items |
       NOT (SIZEOF (['AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL',
       'AIC_NON_MANIFOLD_SURFACE.MAPPED_ITEM',
       'AIC_NON_MANIFOLD_SURFACE.AXIS2_PLACEMENT_3D'] * TYPEOF (it)) = 1)))
       = 0;
  WR2: SIZEOF (QUERY (it <* SELF.items |
       SIZEOF (['AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL',
       'AIC_NON_MANIFOLD_SURFACE.MAPPED_ITEM'] * TYPEOF (it)) = 1)) > 0;
  WR3: SIZEOF (QUERY (mi <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.MAPPED_ITEM' IN TYPEOF (it)) |
       NOT (('AIC_NON_MANIFOLD_SURFACE.'+
       'NON_MANIFOLD_SURFACE_SHAPE_REPRESENTATION'
       IN TYPEOF (mi\mapped_item.mapping_source.mapped_representation))
       AND
       (SIZEOF(QUERY (mr_it <*
       mi\mapped_item.mapping_source.mapped_representation.items |
       ('AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL'
       IN TYPEOF (mr_it)))) > 0 )))) = 0;
  WR4: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (SIZEOF (['AIC_NON_MANIFOLD_SURFACE.FACE_SURFACE',
       'AIC_NON_MANIFOLD_SURFACE.ORIENTED_FACE'] * TYPEOF (fa)) = 1)))
       = 0))) = 0))) = 0;
  WR5: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (f_sf <* QUERY (fa <* cfs.cfs_faces |
       ('AIC_NON_MANIFOLD_SURFACE.FACE_SURFACE' IN TYPEOF (fa))) |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (f_sf))
       OR
       (nmsf_surface_check(f_sf\face_surface.face_geometry))))) = 0))) 
       = 0))) = 0;
  WR6: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (o_fa <* QUERY (fa <* cfs.cfs_faces |
       ('AIC_NON_MANIFOLD_SURFACE.ORIENTED_FACE' IN TYPEOF (fa))) |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF 
       (o_fa\oriented_face.face_element))
       OR
       (nmsf_surface_check
       (o_fa\oriented_face.face_element\face_surface.face_geometry)))))
       = 0))) = 0))) = 0;
  WR7: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (bnds <* fa.bounds |
       NOT (SIZEOF (['AIC_NON_MANIFOLD_SURFACE.EDGE_LOOP',
       'AIC_NON_MANIFOLD_SURFACE.VERTEX_LOOP']
       * TYPEOF (bnds.bound)) = 1))) = 0)))) = 0))) = 0))) = 0;
  WR8: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items|
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (elp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.EDGE_LOOP' IN TYPEOF (bnds.bound)) |
       NOT (SIZEOF (QUERY (oe <* elp_fbnds\path.edge_list |
       NOT ('AIC_NON_MANIFOLD_SURFACE.EDGE_CURVE' IN TYPEOF 
       (oe.edge_element)))) = 0))) = 0)))) = 0))) = 0))) = 0;
  WR9: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (elp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.EDGE_LOOP' IN TYPEOF (bnds.bound)) |
       NOT (SIZEOF (QUERY (oe_cv <* QUERY (oe <* 
       elp_fbnds\path.edge_list |
       'AIC_NON_MANIFOLD_SURFACE.EDGE_CURVE' IN TYPEOF (oe.edge_element)) |
       NOT (SIZEOF (['AIC_NON_MANIFOLD_SURFACE.B_SPLINE_CURVE',
       'AIC_NON_MANIFOLD_SURFACE.CONIC',
       'AIC_NON_MANIFOLD_SURFACE.CURVE_REPLICA',
       'AIC_NON_MANIFOLD_SURFACE.LINE',
       'AIC_NON_MANIFOLD_SURFACE.OFFSET_CURVE_3D',
       'AIC_NON_MANIFOLD_SURFACE.PCURVE',
       'AIC_NON_MANIFOLD_SURFACE.POLYLINE',
       'AIC_NON_MANIFOLD_SURFACE.SURFACE_CURVE'] * 
       TYPEOF (oe_cv.edge_element\edge_curve.edge_geometry)) 
       = 1))) = 0))) = 0)))) = 0))) = 0))) = 0;
 WR10: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (elp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.EDGE_LOOP' IN TYPEOF (bnds.bound)) |
       NOT (SIZEOF (QUERY (oe <* elp_fbnds\path.edge_list |
       NOT (nmsf_curve_check (oe.edge_element\edge_curve.edge_geometry)))) 
       = 0))) = 0)))) = 0))) = 0))) = 0;
 WR11: SIZEOF (QUERY(fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (elp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.EDGE_LOOP' IN TYPEOF (bnds.bound)) |
       NOT (SIZEOF (QUERY (oe <* elp_fbnds\path.edge_list|
       NOT (('AIC_NON_MANIFOLD_SURFACE.VERTEX_POINT' IN TYPEOF
       (oe.edge_element.edge_start))
       AND
       ('AIC_NON_MANIFOLD_SURFACE.VERTEX_POINT' IN
       TYPEOF (oe.edge_element.edge_end))))) 
       = 0))) = 0)))) = 0))) = 0))) = 0;
 WR12: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <*
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (elp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.EDGE_LOOP' IN TYPEOF (bnds.bound)) |
       NOT (SIZEOF (QUERY (oe <* elp_fbnds\path.edge_list |
       NOT ((SIZEOF (['AIC_NON_MANIFOLD_SURFACE.CARTESIAN_POINT',
       'AIC_NON_MANIFOLD_SURFACE.DEGENERATE_PCURVE',
       'AIC_NON_MANIFOLD_SURFACE.POINT_ON_CURVE',
       'AIC_NON_MANIFOLD_SURFACE.POINT_ON_SURFACE'] * TYPEOF
       (oe.edge_element.edge_start\vertex_point.vertex_geometry)) = 1)
       AND
       (SIZEOF (['AIC_NON_MANIFOLD_SURFACE.CARTESIAN_POINT',
       'AIC_NON_MANIFOLD_SURFACE.DEGENERATE_PCURVE',
       'AIC_NON_MANIFOLD_SURFACE.POINT_ON_CURVE',
       'AIC_NON_MANIFOLD_SURFACE.POINT_ON_SURFACE'] * TYPEOF
       (oe.edge_element.edge_end\vertex_point.vertex_geometry)) = 1
       )))) = 0))) = 0)))) = 0))) = 0))) = 0;
 WR13: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <* 
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (vlp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.VERTEX_LOOP' IN TYPEOF (bnds.bound)) |
       NOT ('AIC_NON_MANIFOLD_SURFACE.VERTEX_POINT' IN TYPEOF
       (vlp_fbnds\vertex_loop.loop_vertex)))) = 0)))) = 0))) 
       = 0))) = 0;
 WR14: SIZEOF (QUERY (fbsm <* QUERY (it <* SELF.items |
       'AIC_NON_MANIFOLD_SURFACE.FACE_BASED_SURFACE_MODEL' IN TYPEOF (it)) |
       NOT (SIZEOF (QUERY (cfs <* 
       fbsm\face_based_surface_model.fbsm_faces |
       NOT (SIZEOF (QUERY (fa <* cfs.cfs_faces |
       NOT (('AIC_NON_MANIFOLD_SURFACE.ADVANCED_FACE' IN TYPEOF (fa))
       OR
       (SIZEOF (QUERY (vlp_fbnds <* QUERY (bnds <* fa.bounds |
       'AIC_NON_MANIFOLD_SURFACE.VERTEX_LOOP' IN TYPEOF (bnds.bound)) |
       NOT (SIZEOF (['AIC_NON_MANIFOLD_SURFACE.CARTESIAN_POINT',
       'AIC_NON_MANIFOLD_SURFACE.DEGENERATE_PCURVE',
       'AIC_NON_MANIFOLD_SURFACE.POINT_ON_CURVE',
       'AIC_NON_MANIFOLD_SURFACE.POINT_ON_SURFACE'] * TYPEOF
       (vlp_fbnds\vertex_loop.loop_vertex\vertex_point.vertex_geometry)) 
       = 1))) = 0)))) = 0))) = 0))) = 0;
END_ENTITY;

FUNCTION nmsf_curve_check (cv : representation_item) : BOOLEAN;  
 
(* This function varifies the validity of a curve in the context of a
   non-manifold surface model. Representation_items are
   valid input, however, they are supposed to be curves; otherwise
   this function will return false.
*)

 (* complex subtypes of curve that are both bounded_curve and
    oneof conic, curve_replica, line, or offset_curve_3d are not
    valid
 *)
 IF SIZEOF (['AIC_NON_MANIFOLD_SURFACE.BOUNDED_CURVE',
   'AIC_NON_MANIFOLD_SURFACE.CONIC',
   'AIC_NON_MANIFOLD_SURFACE.CURVE_REPLICA',
   'AIC_NON_MANIFOLD_SURFACE.LINE',
   'AIC_NON_MANIFOLD_SURFACE.OFFSET_CURVE_3D'] * TYPEOF(cv)) > 1
 THEN RETURN(FALSE);
 ELSE

  (* b_spline_curves shall not self-intersect
   *)
  IF (('AIC_NON_MANIFOLD_SURFACE.B_SPLINE_CURVE' IN TYPEOF (cv)) AND
    (cv\b_spline_curve.self_intersect = FALSE) OR
    (cv\b_spline_curve.self_intersect = UNKNOWN))
  THEN RETURN(TRUE);
  ELSE

    (* conics and lines are valid curve types
     *)
    IF SIZEOF (['AIC_NON_MANIFOLD_SURFACE.CONIC',
    'AIC_NON_MANIFOLD_SURFACE.LINE'] * TYPEOF (cv)) = 1 THEN
      RETURN(TRUE);
    ELSE

      (* a curve_replica shall reference a valid curve
       *)
      IF 'AIC_NON_MANIFOLD_SURFACE.CURVE_REPLICA' IN TYPEOF(cv) THEN
        RETURN (nmsf_curve_check(cv\curve_replica.parent_curve)); 
      ELSE 
 
        (* an offset_curve_3d shall not self-intersect and
           shall reference a valid curve; a polyline is not a
           valid basis_curve
         *)
        IF (('AIC_NON_MANIFOLD_SURFACE.OFFSET_CURVE_3D' IN TYPEOF (cv)) 
          AND
          ((cv\offset_curve_3d.self_intersect = FALSE) OR
          (cv\offset_curve_3d.self_intersect = UNKNOWN))
          AND
          (NOT ('AIC_NON_MANIFOLD_SURFACE.POLYLINE' IN TYPEOF
          (cv\offset_curve_3d.basis_curve)))) THEN
          RETURN (nmsf_curve_check(cv\offset_curve_3d.basis_curve)); 
        ELSE 
 
          (* a pcurve shall reference a valid curve and a valid
             basis_surface
           *)
          IF 'AIC_NON_MANIFOLD_SURFACE.PCURVE' IN TYPEOF(cv) THEN 
            RETURN ((nmsf_curve_check
            (cv\pcurve.reference_to_curve\representation.items[1]))
            AND
            (nmsf_surface_check(cv\pcurve.basis_surface)));
          ELSE 
 
            (* a surface_curve references a curve_3d and one or
               two pcurves or one or two surfaces or one of
               each; all of these references shall be valid
             *)
            IF 'AIC_NON_MANIFOLD_SURFACE.SURFACE_CURVE' IN TYPEOF(cv) THEN 

              (* if the curve reference is correct, check also the rest
               *)
              IF nmsf_curve_check(cv\surface_curve.curve_3d) THEN
                REPEAT i := 1 TO SIZEOF
                (cv\surface_curve.associated_geometry);

                  (* do for one or two associated_geometrys:
                   *)
                  IF 'AIC_NON_MANIFOLD_SURFACE.SURFACE' IN 
                    TYPEOF (cv\surface_curve.associated_geometry[i]) THEN  
                    IF NOT nmsf_surface_check
                      (cv\surface_curve.associated_geometry[i]) THEN  
                      RETURN(FALSE);  
                    END_IF;  
                  ELSE  
                    IF 'AIC_NON_MANIFOLD_SURFACE.PCURVE' IN TYPEOF 
                      (cv\surface_curve.associated_geometry[i]) THEN  
                      IF NOT nmsf_curve_check
                        (cv\surface_curve.associated_geometry[i]) THEN 
                        RETURN(FALSE);  
                      END_IF;  
                    END_IF;  
                  END_IF; 
                END_REPEAT;  
                RETURN(TRUE);
              END_IF; 
            ELSE

              (* a polyline shall have at least 3 points 
               *)
              IF 'AIC_NON_MANIFOLD_SURFACE.POLYLINE' IN TYPEOF(cv) THEN
                IF (SIZEOF (cv\polyline.points) >= 3) THEN RETURN (TRUE);
                END_IF;
              END_IF;
            END_IF; 
          END_IF; 
        END_IF; 
      END_IF; 
    END_IF; 
  END_IF; 
 END_IF; 
 (* FALSE is returned if the input parameter cv is not a valid curve.
  *)
 RETURN (FALSE); 
END_FUNCTION;

FUNCTION nmsf_surface_check (surf : surface) : BOOLEAN;

(* This function varifies the validity of a surface in the
   context of a non-manifold surface model.
*)

  (* elementary_surfaces are valid surface types
   *)
  IF 'AIC_NON_MANIFOLD_SURFACE.ELEMENTARY_SURFACE' IN TYPEOF(surf) THEN
    RETURN(TRUE);
  ELSE 

    (* a swept_surface shall have a valid sweeping curve
     *)
    IF 'AIC_NON_MANIFOLD_SURFACE.SWEPT_SURFACE' IN TYPEOF (surf) THEN 
      RETURN (nmsf_curve_check(surf\swept_surface.swept_curve));  
    ELSE 
 
      (* an offset_surface shall not self-intersect and shall
         reference a valid surface
       *)
      IF (('AIC_NON_MANIFOLD_SURFACE.OFFSET_SURFACE' IN TYPEOF (surf)) AND
        (surf\offset_surface.self_intersect = FALSE) OR 
        (surf\offset_surface.self_intersect = UNKNOWN)) THEN
        RETURN (nmsf_surface_check(surf\offset_surface.basis_surface));
      ELSE 
 
        (* a surface_replica shall have a valid parent surface
         *)
        IF 'AIC_NON_MANIFOLD_SURFACE.SURFACE_REPLICA' IN TYPEOF(surf) THEN 
          RETURN(nmsf_surface_check(surf\surface_replica.parent_surface)); 
        ELSE

          (* a b_spline_surface shall not self-intersect
           *)
          IF (('AIC_NON_MANIFOLD_SURFACE.B_SPLINE_SURFACE' IN TYPEOF(surf))
            AND
            (surf\b_spline_surface.self_intersect = FALSE) OR
            (surf\b_spline_surface.self_intersect = UNKNOWN)) THEN
            RETURN(TRUE);
          END_IF;
        END_IF; 
      END_IF; 
    END_IF; 
  END_IF; 
  RETURN(FALSE); 
END_FUNCTION;

END_SCHEMA; (* aic_non_manifold_surface *)
